mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
ddfc90df92
x-ref: [Flakiness Metrics](https://app.datadoghq.com/ci/test-runs?query=test_level%3Atest%20env%3Aci%20%40git.repository.id%3Agithub.com%2Fvercel%2Fnext.js%20%40test.service%3Anextjs%20%40test.status%3Afail%20%40test.name%3A%22streaming%20responses%20cancel%20inner%20stream%20after%20disconnect%20edge%20pages%20api%20cancels%20stream%20making%20progress%22&agg_m=count&agg_m_source=base&agg_t=count¤tTab=overview&eventStack=&fromUser=false&index=citest&start=1728463943572&end=1729068743572&paused=false) In #71163, we added to the `Streamable` handling the case where the request might already be aborted before the response was sent or had a chance to be consumed. For the "cancels stream making progress" however, the request may not be aborted, and instead only the response is destroyed, leading to the `cancel` method of the `Streamable` being called, but not the `abort` method. To handle all cases, we're now resolving the `finished` promise of the `Streamable` when either `abort` or `cancel` are called.
31 lines
645 B
TypeScript
31 lines
645 B
TypeScript
import { Deferred, sleep } from './sleep'
|
|
|
|
export function Streamable(write: number) {
|
|
const encoder = new TextEncoder()
|
|
const canceled = new Deferred()
|
|
const aborted = new Deferred()
|
|
let i = 0
|
|
|
|
const streamable = {
|
|
finished: Promise.any([canceled.promise, aborted.promise]).then(() => i),
|
|
|
|
abort() {
|
|
aborted.resolve()
|
|
},
|
|
stream: new ReadableStream({
|
|
async pull(controller) {
|
|
if (i >= write) {
|
|
return
|
|
}
|
|
|
|
await sleep(100)
|
|
controller.enqueue(encoder.encode(String(i++)))
|
|
},
|
|
cancel() {
|
|
canceled.resolve()
|
|
},
|
|
}),
|
|
}
|
|
return streamable
|
|
}
|