Search code examples
javascriptdeno

Handling client disconnect/abort during streaming response in `Deno.serve`


I have some Deno server code that looks roughly like this:

Deno.serve((req) => {
  let asyncIterator = getChunkIterator(req.url);

  const stream = new ReadableStream({
    async pull(controller) {
      try {
        const { value, done } = await asyncIterator.next();
        if (done) {
          controller.close();
          return;
        }
        controller.enqueue(value);
      } catch (err) {
        controller.error(err);
      }
    }
  });
  
  let response = new Response(stream);
  return response;
});

The response streaming can take several seconds, and the client may disconnect half-way through. I need to detect this so that I can stop the (separate) "worker" server that is producing the chunks of data for that client.

I have no idea how to do this, since with Deno.serve you just return the Response object, rather than being given a stream to write to.


Solution

  • You need to implement cancel method of the ReadableStream

    Starting from Deno version 1.36.4, connection drops will be accurately detected when responding with a ReadableStream, and the cancel method will be called with the reason "resource closed" (implemented in this commit)

    Deno.serve((req) => {
      let asyncIterator = getChunkIterator(req.url);
    
      const stream = new ReadableStream({
        async pull(controller) {
         /* ... */
        },
    
        cancel(reason) {
          // reason === 'resource closed' when connection drops
          // cleanup your resource
        }
      });
      
      let response = new Response(stream);
      return response;
    });