429 vs 503

A while back I was involved in a discussion around using 429 instead of 503 in order to tell clients they should back off a little. And there are some good arguments for both. Here are my thoughts.

The 429 and 503 status code both suggest you use the Retry-After header to let a client know that they should back off a specific time. So from a general perspective they serve the same purpose so which one should you choose?

Generally speaking 4xx errors should be returned when the user did something wrong while 5xx is returned when the error is "the server's fault". As such a temporary error such as a lost connectivity to a dependency should be returned as a 503. But if the client is breaking a contract by making too many requests over a certain time period then 429 is the best option. But what if there is no real contract but the client is making so many requests that your service is essentially experiencing a DoS attack? In my opinion you want to use 503 in that case since the client is not really breaking a predefined contract; you are just approaching the limits of your service. I think this is obvious if you think about the case where your DoS prevention algorithm is to reject any request if you already have X number of requests. It would be weird for a client who have never connected to you before getting a 429 stating it has violated the rate of which requests can be accepted.

Another important aspect is that 503 has an old well established error code. Even old implementations, including proxies will know how to handle a 503 error while 429 is less likely to be handled correctly by older clients. This is however also the downside of 503. A client receiving a 503 is not necessarily receiving it from your service; your web server, load balancer or even the client's web proxy might return 503 so when the customer complaints they are receiving 503s you first need to figure out who is returning it. So from a trouble shooting perspective returning 429 is very tempting.

In my opinion the rate limited contract where 429 makes sense should not be defined as a number of requests per second nor per minute. I think you want your contract to be defined in requests per hour or even days so that the client can get results even if it makes requests quite spikey. As such I expect the Retry-After time in the 429 response to be long. Relatively speaking. 503s on the other hand I expect to have very short retry after times; typically just a few seconds or a minute or two at the most. All that is for the majority of the time and not necessarily all the time.

So if you ask me you should only use 429s for a single, very specific case; when your contract clearly has a limit of number of requests per user. And by user I mean a real user or another service.

No comments:

Post a Comment