[whatwg/fetch] Aborting a settled request (and why abort should be synchronous) (#448)

Documenting a side-conversation with @jakearchibald via Twitter DM spun off from #447:

Whatever approach we go with for aborting a fetch, there needs to be the question of what should happen when code tries to abort a fetch *that has already finished*, in one manner or another (completed, timed out, server hung up, already aborted by the exact same code, whatever).

(Note that I'm using the term "a fetch" to refer to an in-progress request dispatched by a caller of `fetch()`, instead of "a request", as Request right now can describe the object that a Service Worker receives as part of the `fetch` event that describes an *inert request that has yet to be made*, and I am [taking pains to make the distinction](https://github.com/whatwg/fetch/issues/447#issuecomment-270444061).)

You *could* make the case that this is harmless, especially in a design where aborted fetches don't resolve/reject in the same way as a normal request/response (the way some of the Canceling proposals worked, for instance, especially the ones with a notion of "signaling disinterest and unsubscribing from the response").

However, my stance is that cancelling a request should be a *synchronous operation* that *throws an error* if the request has already terminated.

It should be synchronous (not that I've really seen any contention around this, but just to be clear) because, as soon as the request has been aborted, there's no more room for any events in its lifecycle (not counting events *around* the lifecycle, such as rejecting any Promises etc waiting on the fetch, which should of course be triggered async as normal). Even if there were any I/O relating to the request after we've aborted it, it would no longer be considered part of the fetch. Once it's aborted, the fetch is closed - there's no in-between. A fetch has either finished or it hasn't, and once it's finished, it can't finish again.

It's my stance that attempting to abort a fetch that's *already* closed should throw an error (even if aborting doesn't cause the fetch to terminate, which, for what it's worth, I think would be wrong). This is the case I laid out to Jake:

- It's really easy to avoid aborting a fetch that's already finished: whatever has the `.abort()` method (Request, FetchController, whatever) ought to have a `.closed` (or `.finished` or whatever) right next to it that, if your fetch-aborting code may potentially act on an already-finished fetch, it can check for (ie `if (!rq.closed) rq.abort()` or `if (!rq.status.finished) rq.control.stop()` or whatever).

- It's not hard to imagine an edge case where this should be handled but could be overlooked. If a developer mistakenly attempts to abort a finished request, they get an error they can easily modify the code to avert: if a developer mistakenly aborts a resolved fetch that should have been handled differently and it *doesn't* throw an error, they'll get *no indication of what's going wrong*, short of hopping in the debugger and fiddling with breakpoints for an hour.

## "Double resolution" errors

Say a Service Worker could be written for an endpoint that takes a long time to find invalid records, and has a quota for number of invalid requests that can be initiated. Under the assumption that all requests for resources it discovers are invalid will still be in progress when it aborts them, the service worker decrements the "Failed request" quota every time it aborts a fetch. The SW also handles fetches that come back as errors by decrementing the quota. If the endpoint speeds up one day, and all the requests that were previously being aborted *before* finishing are now being aborted *after*, with silent aborts, the quota would be depleted at *double the normal rate*, with *no indication as to why*. If trying to abort a request that's already finished throws an error, this pops the applicable error, and potentially averts whatever wrong behavior would have ensued after the double-abort.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/fetch/issues/448

Received on Wednesday, 4 January 2017 20:25:02 UTC