Multiple Simultaneous HTTP Patch Requests

And what to do about it

The Project

For my Flatiron Phase 3 final project, my partner and I made a cute little game called Spelling Bee.

The models on the Rails backend were:

A game has many sessions (two to be exact, since there are two players per game), and a player has many games. The Session model is our join.

The Problem

For every game that is started, two sessions are created, one for each player. These link a unique player with a unique game so that we can track scores. Every time a game is finished we need to update the winner of the game (a string of the player’s name), and both sessions with the associated player’s score. So, we figured, let’s just write three HTTP PATCH requests to the backend and get those three items updated. The code looked something like this:

The result of these three simultaneous requests was a very strange bug. I put a byebug in the ‘update’ controller action to stop the code running there and I found that when calling ‘self.id’ repeatedly I would get alternating session id’s. Ultimately the process would error out with a 500 Internal Server Error. This is a generic HTTP error message that tells us the server encountered some issue that would not allow it to fulfill its request. Sounds about right.

On a deeper level, the issue is the asynchronous nature of JavaScript execution. Essentially a JavaScript engine will come across some code and begin executing it, but also move along to other code in the program that needs to be run. It makes for faster, more efficient processing, but we must be careful in exactly this situation, when timing does matter.

The Solution

So, you’re dying to know, how did you fix it, Dana?! Through some troubleshooting we confirmed that if we finished a game but only ran one of those three requests, it would correctly update in the database. So the question was, how do we require the code to complete one request before beginning the next? Enter .then.

.then is used on most fetch() calls to delay a portion of code. It is telling the JavaScript to wait until the Promise is returned, indicated that the fetch request is finished, to move on to that bit of code. Usually we want to wait for some information to come back from the database before updating our front end. It might look like this:

For Spelling Bee, we used .then after each fetch() to create a cascade of HTTP requests so that each one would not run until the one before it was finished. We called a function containing the next fetch() call inside of each fetch()’s .then statement:

In our scenario it did not matter the order of these HTTP requests, though it could be that a request depends on another one happening before it, in which case you could organize the functions in your .then statements accordingly.

Another Option

For our purposes this worked well and fixed the bug, though there is another option that has recently become available. The ECMAScript 2017 includes async functions and the ‘await’ keyword. The example from MDN’s documentation is:

An async function is an instance of the AsyncFunction constructor, and the ‘await’ keyword is used inside of the function to tell the engine to hold off on executing the next bit of code until a promise is received from the function directly after the ‘await’ keyword. Test the above code in node or repl.it and you’ll see that the console prints ‘calling’, then after 2 seconds it prints ‘resolved’.

We didn’t have the time to refactor our code to include async/await but it is a slick solution to this common problem, and I think it is more expressive of what we were actually trying to accomplish. Add this to the refactor list!

Hi! I am a bassoonist and a software engineer, a mash-up of the obscure and the mainstream, and I’m based in Seattle.