HTTP Retry-After in an OTA Client: Parse Dates and Delays Without Resetting the Campaign Deadline

Parse Retry-After into a validated earliest retry time, then compare that time with the existing campaign deadline. Do not restart the campaign budget when a server asks the client to wait. If the requested delay cannot fit, defer or end the attempt under policy rather than retrying earlier by silently clipping the delay.

This guide applies RFC 9110 HTTP semantics to an original OTA-client scheduling contract. It does not claim a particular HTTP library implements the proposed parser or policy. The fixtures below are test designs; no parser, HTTP server or target was executed.

1. Establish exactly which response is being handled

RFC 9110 section 10.2.3 permits either an HTTP-date or a nonnegative decimal count of seconds. The relative delay is anchored to receipt of the response. With 503 it describes expected unavailability; with a redirection it requests a minimum wait before following the redirect.

Record the response status, request identity, receipt timestamp and retry-policy revision. Header parsing alone does not decide whether retrying that request is appropriate. An authorization failure, unsupported artifact or invalid client configuration needs its own classification.

Keep the installer separate from artifact retrieval. Waiting to retry a harmless download request should not cause the client to restart an installation that has already begun. State-changing management requests require the service’s established idempotency or reconciliation contract.

2. Separate syntax, representation and policy errors

Input class Parser result Scheduling decision
Decimal seconds that fit the supported representation. Valid relative delay. Convert safely from the receipt anchor.
Valid date and usable UTC evidence. Valid absolute time. Convert once to the scheduling clock.
Valid date but unknown clock quality. Syntax valid; timing unresolved. Hold or use the separately approved uncertainty policy.
Malformed value. Invalid field. Record the defect and apply bounded fallback policy.
Valid value too large to represent or admit. Unsupported delay or exhausted budget. Defer; do not turn overflow into an immediate retry.

Use a bounded parser that consumes the entire field. Reject signs, fractional seconds and trailing junk in the decimal form. Check overflow before multiplication into milliseconds or scheduler ticks. A very long decimal string deserves a bounded outcome even if a host language offers arbitrary-size integers.

Do not split the value at every comma: a valid date contains one. Require the HTTP layer to expose duplicate-field conditions clearly, and define a conservative policy for ambiguous repeated values. Do not choose whichever fragment produces the shortest delay.

A Retry-After value is parsed and converted with clock and range checks before its earliest retry plus request reserve is compared with the unchanged campaign deadline.
Original scheduling model. The example separates RFC field semantics from product-specific admission and uncertainty policies.

3. Qualify all HTTP date forms

RFC 9110 section 5.6.7 requires timestamp recipients to accept IMF-fixdate and the two obsolete HTTP-date forms; senders use IMF-fixdate. Dates represent UTC. The RFC also defines the two-digit-year interpretation rule for the obsolete RFC 850 form.

Use the HTTP library’s documented date parser only after checking its actual accepted grammar, bounds and error reporting. A generic email-date parser may be more permissive than the desired HTTP contract. A convenient parser that accepts only the modern form is also insufficient for the recipient requirement.

For the following synthetic vectors, assume a known UTC receipt time of 14 October 2026 at 11:18:00. The expected delay is 120 seconds in all four rows:

Field value Form
120 Relative seconds.
Wed, 14 Oct 2026 11:20:00 GMT IMF-fixdate.
Wednesday, 14-Oct-26 11:20:00 GMT Obsolete RFC 850 form.
Wed Oct 14 11:20:00 2026 Obsolete asctime form.

Add vectors for invalid calendar dates, trailing characters, the two-digit-year boundary, maximum supported timestamps and a leap-second policy consistent with the selected parser. Preserve the exact parser version and expected classification with each fixture.

4. Convert clock domains once

Capture a monotonic receipt time and the corresponding usable UTC estimate. For a future absolute date, derive the remaining delay from that pair, account for the approved clock-uncertainty bound, and schedule against the monotonic clock. Rounding should not make the retry occur earlier than the accepted delay.

A wall-clock correction after scheduling should not restart the wait or suddenly make an old timer expire. Choose a scheduling clock whose behavior across suspend matches the product’s budget definition. Reboots require an explicit recovery rule because a prior boot’s monotonic timestamp cannot simply be reused.

If UTC is unavailable, a syntactically valid date remains unresolved. Do not assume an unverified response Date field establishes trustworthy time. An approved time-recovery path or a deferred campaign state is preferable to inventing a zero delay.

A past date contributes no future wait under this proposed policy, but it does not reset the client’s existing backoff or create an unbounded immediate retry loop. Apply the same distinction to a relative value of zero.

5. Preserve the original deadline

Let D be the existing overall operation deadline on the chosen monotonic clock. Let E be the later of the server-derived earliest retry time and the client’s existing earliest retry time. Reserve R for the bounded next request and cleanup. Admit it only when E plus R fits within D, using checked arithmetic.

This is a product admission rule, not an HTTP requirement. If additional scheduling spread is used, it must not advance the request before E. Recheck eligibility and remaining budget when the timer fires because delayed scheduling can consume the reserved time.

In a hypothetical case, D is 1,000 seconds, the response arrives at 700, and the server asks for 250 seconds. E is at least 950. A required 100-second request reserve does not fit. The client records a deferral; replacing the server’s delay with 100 seconds would change the meaning of the response.

6. Test repeated responses and stale timers

  • Feed 0, 000120, negative, fractional, empty and oversized decimal inputs.
  • Exercise all date forms with known, uncertain and unavailable UTC.
  • Move wall time forward and backward after a timer is scheduled.
  • Return repeated valid Retry-After values without extending D.
  • Expire or supersede the campaign while the retry timer is pending.
  • Wake late and verify the client does not start work after its budget is exhausted.

Each scheduled callback should carry the campaign and request generation. A stale callback must not restart an obsolete download after a newer decision has superseded it. Keep valid server delay, local policy delay, parser failure and budget exhaustion as distinct diagnostic reasons.

The deliverable is a parser fixture and clock/budget contract that survives malformed input and repeated unavailability. It preserves server timing intent without allowing one header to grant an endless campaign extension.

Similar Posts