[HN Gopher] Retry XMLHttpRequest Carefully
___________________________________________________________________
Retry XMLHttpRequest Carefully
Author : aparks517
Score : 20 points
Date : 2022-06-28 18:11 UTC (4 hours ago)
(HTM) web link (lofi.limo)
(TXT) w3m dump (lofi.limo)
| e12e wrote:
| Very nice write-up. I'd be curious to see it using fetch rather
| than the older xhr Api - that would make more sense as a library
| _today_ I think? Or are there compelling reasons to stick with
| xhr in a post-ie world?
| dreamcompiler wrote:
| I still use xhr because of familiarity. Using a javascript
| closure as a callback in xhr works quite well and seems _much_
| easier to me than dealing with the promises that are required
| for fetch. (I understand what promises are; I just think the
| ones in javascript are poorly-defined.)
|
| https://pouchdb.com/2015/05/18/we-have-a-problem-with-promis...
| mhink wrote:
| From the end of the article you linked:
|
| > Awaiting async/await
|
| > That's the point I made in "Taming the asynchronous beast
| with ES7", where I explored the ES7 async/await keywords, and
| how they integrate promises more deeply into the language.
| Instead of having to write pseudo-synchronous code (with a
| fake catch() method that's kinda like catch, but not really),
| ES7 will allow us to use the real try/catch/return keywords,
| just like we learned in CS 101.
|
| > This is a huge boon to JavaScript as a language. Because in
| the end, these promise anti-patterns will still keep cropping
| up, as long as our tools don't tell us when we're making a
| mistake.
|
| Async/await is extremely well-supported and reliable in the
| ecosystem now, and allows you to express Promise-based
| asynchronous flows with a much more natural syntax. I highly
| recommend that you take a look, as it pretty much obviates
| all the pain points mentioned in the linked article.
| aparks517 wrote:
| Thank you for your kind words! For lofi.limo I support back to
| Chrome 49 and Firefox 52 (the last versions available for
| Windows XP), which I /think/ both have Fetch, so I could have
| probably used it here.
|
| Fetch has about the same capabilities as XHR, so it should be a
| drop-in replacement in this project. Let's call it an exercise
| for the reader! ;)
| chrismorgan wrote:
| > _which I /think/ both have Fetch_
|
| Yes: https://caniuse.com/fetch.
| rbirkby wrote:
| Just use axios and https://www.npmjs.com/package/retry-axios
| eurasiantiger wrote:
| Or node-fetch and @adobe/node-fetch-retry.
| kerblang wrote:
| Am I wrong or is this going to retry 404's and other 4xx things
| that it shouldn't retry?
| joshstrange wrote:
| This post reminded of a /fun/ bug I ran into at my last job. The
| root of the issue was our server was returning a 408 timeout
| error when something timed out on the backend. Astute readers
| might immediately notice an issue with that code, mainly that
| it's for a /client/ timeout not 504 (server timeout).
|
| Since we controlled the client and server you might think it
| doesn't matter much, as long as the client knows how to handle a
| 408 everything should be fine right? Well not exactly. We had a
| number of pages/endpoints that would be overwhelmed when there
| was too much data on the backend for a given user/company (which
| was it's own issue but let's just take that as fact for this and
| move on). We dutifully sent back 408's and knew that we needed to
| optimize or chunk those endpoints in the future.
|
| The problem was the code that timed out would keep running until
| it finished (or hit a different timeout). On it's own this isn't
| the end of the world, the server does work that never gets sent
| to the client and essentially is thrown away. The problem was
| some of these endpoints would run very heavy queries that could
| bring down our database if enough of them were run in a short
| window. Even more confusing it appeared as if our server was
| running multiple of these queries for only 1 request.
|
| We were using Akka (Actor-based) in our backend and thought maybe
| something was misconfigured or that we might accidentally be
| dropping duplicate messages into the queues that caused multiple
| queries to get fired off. We fought with this on/off for months
| (you know, something else is always a higher priority). Finally
| we tracked down that the browser was sending multiple requests.
| This was only clear when testing in a isolated dev environment
| with no other traffic and you could clearly see a second request
| being made after the first one timed out. What was extremely
| frustrating is Chrome did not show this second request in the dev
| tools, it only showed the initial request.
|
| After more digging and a little luck I stumbled across a
| "feature" of browsers where they will retry the same request
| under certain circumstance and they wouldn't show that in dev
| tool. A 408 was one of those cases. Switching to the correct
| code, 504, immediately fixed our odd self-DDOS against our DB.
|
| Obviously this was the fault of whoever initially defined
| `TIMEOUT = 408` somewhere in our HTTP error codes class but to
| this day I feel like Chrome should have had some indication that
| it was firing off another request. If you left the tab open
| Chrome would just keep retrying and slowly overwhelm the DB with
| heavy queries until it fell over.
| pgt wrote:
| Thanks! Did not know some browsers would invisibly retry
| requests that returned 408.
| indemnity wrote:
| Really curious what the use case is for _dev_ tools hiding a
| network request from you?
|
| Sure, don't display it in the UI, but if the browser is
| retrying something I sure want to know about it when debugging!
|
| Odd.
| joshstrange wrote:
| Yeah, that was my thought as well. It threw me for a loop
| because I never would have expected that my browser dev tools
| would hide something like that. It was a core tenant of my
| debugging that was broken.
| noduerme wrote:
| At this point I like to wrap my remoting code (including optional
| retries) into async functions that return a promise. The promise
| resolves with a result from the server, or rejects with any sort
| of error that can come from an XHR (or now, fetch), and the
| consumer can decide what to do with that.
|
| In my software I almost never do automatic retries, rather I warn
| the user that there was a connection error if necessary, and
| revert whatever state was waiting on a call. In my view anything
| that can fail silently probably does not need to be retried right
| now.
| cratermoon wrote:
| This is a good introduction to the subject. At the end you might
| want to mention rate limiting, truncation (giving up after a
| specified number of retries) and, for the most sophistication,
| circuit breakers.
| aparks517 wrote:
| Thank you for your suggestions! I'll see if I can write a few
| intelligent sentences on these (somewhat more advanced)
| subjects.
___________________________________________________________________
(page generated 2022-06-28 23:02 UTC)