monitorStream in packages/deno/src/utils/streaming.ts:79 builds a ReadableStream with no cancel handler, so cancelling the returned stream never cancels the source.
{"pullsAfterCancel":3,"sourceCancelled":false,"spanEnded":true}
later: {"pulls":3,"sourceCancelled":false,"spanEnded":true}
The span does end, which is the important part. But the source is left un-cancelled. For an SSE or LLM response, the upstream producer keeps running after the client disconnects. Cloudflare avoids this by piping through a TransformStream, which forwards cancellation.
Work item. Add a cancel(reason) to the ReadableStream underlying source that calls reader.cancel(reason), or switch to the Cloudflare pipeThrough(new TransformStream(...)) shape. Add a unit test asserting the source's cancel fires.
monitorStreaminpackages/deno/src/utils/streaming.ts:79builds aReadableStreamwith nocancelhandler, so cancelling the returned stream never cancels the source.The span does end, which is the important part. But the source is left un-cancelled. For an SSE or LLM response, the upstream producer keeps running after the client disconnects. Cloudflare avoids this by piping through a
TransformStream, which forwards cancellation.Work item. Add a
cancel(reason)to theReadableStreamunderlying source that callsreader.cancel(reason), or switch to the CloudflarepipeThrough(new TransformStream(...))shape. Add a unit test asserting the source'scancelfires.