Skip to content

fix: Retry on 408 and respect Retry-After header#426

Open
andehen wants to merge 5 commits intomasterfrom
be-complient-on-retries
Open

fix: Retry on 408 and respect Retry-After header#426
andehen wants to merge 5 commits intomasterfrom
be-complient-on-retries

Conversation

@andehen
Copy link
Contributor

@andehen andehen commented Feb 6, 2026

Problem

The SDK failed 2 of 29 compliance tests:

  • Retries On 408: 408 (Request Timeout) was treated as a non-retryable client error, so the SDK never retried.
  • Respects Retry-After Header: The backoff library's exponential backoff ignored the Retry-After response header, so the SDK didn't wait the server-requested delay before retrying.

Changes

  • posthog/request.py: Added retry_after field to APIError. Extract the Retry-After header from error responses and pass it through.
  • posthog/consumer.py: Replaced backoff.on_exception with a manual retry loop that uses the Retry-After value when present and falls back to exponential backoff (2^attempt seconds, capped at 30s) otherwise. Added 408 to the set of retryable status codes alongside 429.

Testing

  • All 621 existing unit tests pass.
  • All 29 SDK compliance tests pass (previously 27/29).

408 (Request Timeout) was incorrectly treated as a non-retryable client
error. Retry-After response headers were ignored during backoff. Replace
backoff library usage with a manual retry loop that honours Retry-After
when present and falls back to exponential backoff otherwise.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

andehen and others added 2 commits February 6, 2026 13:58
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Retry-After can be seconds or an HTTP-date per RFC 7231. Fall back to
email.utils.parsedate_to_datetime when the numeric parse fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

posthog-python Compliance Report

Date: 2026-02-06 13:05:31 UTC
Duration: 159366ms

✅ All Tests Passed!

29/29 tests passed


Capture Tests

29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 517ms
Format Validation.Event Has Uuid 1507ms
Format Validation.Event Has Lib Properties 1507ms
Format Validation.Distinct Id Is String 1506ms
Format Validation.Token Is Present 1507ms
Format Validation.Custom Properties Preserved 1507ms
Format Validation.Event Has Timestamp 1506ms
Retry Behavior.Retries On 503 9518ms
Retry Behavior.Does Not Retry On 400 3504ms
Retry Behavior.Does Not Retry On 401 3510ms
Retry Behavior.Respects Retry After Header 9509ms
Retry Behavior.Implements Backoff 23533ms
Retry Behavior.Retries On 500 7504ms
Retry Behavior.Retries On 502 7513ms
Retry Behavior.Retries On 504 7510ms
Retry Behavior.Max Retries Respected 23518ms
Deduplication.Generates Unique Uuids 1508ms
Deduplication.Preserves Uuid On Retry 7510ms
Deduplication.Preserves Uuid And Timestamp On Retry 14522ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 7509ms
Deduplication.No Duplicate Events In Batch 1504ms
Deduplication.Different Events Have Different Uuids 1507ms
Compression.Sends Gzip When Enabled 1506ms
Batch Format.Uses Proper Batch Structure 1507ms
Batch Format.Flush With No Events Sends Nothing 1005ms
Batch Format.Multiple Events Batched Together 1505ms
Error Handling.Does Not Retry On 403 3508ms
Error Handling.Does Not Retry On 413 3508ms
Error Handling.Retries On 408 7513ms

andehen and others added 2 commits February 6, 2026 14:00
When APIError.status is "N/A" (no HTTP status), treat it as
non-retryable to avoid unexpected retry loops on errors the SDK
cannot classify.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verify time.sleep is called with the Retry-After value when present,
uses exponential backoff (2^attempt) when absent, and that 408 is
retried.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@andehen andehen requested review from a team and jose-sequeira February 6, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant