0

I have a endpoint in koa, that loads much data from the database and then calculates some results based on it. This can take some seconds.

What happens to a request, if the browser cancels it? Like the browser tab gets closed etc.

For example, would cache.c be filled even if the browser canceled or is koa smart enough to simply stop any actions it started for this request?

const cache = {}
router.get('/data', function *(next) {

  if (cache.c) return this.body = cache.c

  // somewhere here the browser cancels the request
  //---
  const a = yield db.getA()
  const b = yield db.getB()
  cache.c = yield calculateC(a,b)
  //---

  this.body = cache.c

})
K..
  • 4,044
  • 6
  • 40
  • 85

1 Answers1

1

Your generator function will get yielded/evaluated in its entirety regardless of when the request socket closes (e.g. user closes the tab).

Halting further generator execution just because the socket closes isn't an assumption Koa can make.

For instance, imagine if Koa did auto-halt generator execution and the user closes the socket before yield query('ROLLBACK') has a chance to clean up the db connection. Now you have a botched db connection stuck in the pool. Maybe there are even better reasons than that.

So, yes, Koa keeps executing your generator function until it's finished, at which point the response bubbles back up through your middleware and back to Koa's control where it goes nowhere since the socket is closed.

If you want to know when the user has closed the tab so you can implement your own short-circuiting behavior, you can listen for the "close" event on the request socket:

const cache = {}
router.get('/data', function *(next) {
  if (cache.c) return this.body = cache.c;

  var closed = false;
  this.request.socket.on('close', function() {
    closed = true;
  });

  if (closed) return;
  const a = yield db.getA();
  if (closed) return;
  const b = yield db.getB();
  if (closed) return;
  cache.c = yield calculateC(a,b);

  this.body = cache.c;
})
danneu
  • 9,244
  • 3
  • 35
  • 63
  • Good to know :) My idea was to save the results of long running calculations, so that a user can reclaim them if they come back. – K.. Dec 21 '15 at 14:04
  • 1
    In that case, you may want to just consider a background processing pattern. In the route, insert an incompleted job in the jobs table. In a background queue or a cron job or a setInterval loop or even just after you've returned the response to the user, process jobs and set their status to "completed". When the user checks their page, you can display "still being processed" or the result of the task. Then you don't need to make the user synchronously wait for a computation to complete, and you can do so regardless of whether they've closed the tab. – danneu Dec 22 '15 at 18:21