Skip to content

Retry Grain API rate limits with exponential backoff - #17

Draft
dplakon wants to merge 1 commit into
mainfrom
grain-client-rate-limit-retry
Draft

Retry Grain API rate limits with exponential backoff#17
dplakon wants to merge 1 commit into
mainfrom
grain-client-rate-limit-retry

Conversation

@dplakon

@dplakon dplakon commented Aug 20, 2026

Copy link
Copy Markdown

Problem

Today's daily run of scripts/fetch_daily_meetings.py failed twice with:

RuntimeError: Grain API 429 on GET /recordings?includeParticipants=true&cursor=...: Too Many Requests

Two issues combined to make this fatal:

  • list_all_recordings walks up to 100 pages back-to-back with no delay, so a busy account reliably trips Grain's rate limit.
  • _get raised on the first non-2xx response, so one rate-limited page aborted the entire run — even though the earlier pages had succeeded.

hydrate_with_participants has the same problem: it makes one request per recording of the target day with no pacing.

Changes

  • Added _request, a shared GET helper that retries 429 and transient 500/502/503/504/network errors with exponential backoff (6 attempts, starting at 2s), honoring the Retry-After header when Grain provides one.
  • _get and get_transcript_text both route through the new helper, so transcript fetches in the per-meeting processor get the same protection.
  • Added a small pause between paginated list requests and between per-recording hydration requests, tunable via the GRAINIAC_PAGE_DELAY env var (default 1.0 seconds).
  • Retries log to stderr so a slow run is distinguishable from a hung one.

Verification

Before this change the fetch failed on the second page of pagination on two consecutive attempts, ~45s apart. After the change, the same command completed end to end:

$ python scripts/fetch_daily_meetings.py today
Resolved 'today' to 2026-08-19 (timezone: America/Los_Angeles)
Fetching recordings for 2026-08-19...
Fetched 2000 total recordings
Found 10 recordings on 2026-08-19
Hydrating 10 recordings with participant data...
Found 10 external customer meetings

The 10 meetings were then handed off to per-meeting child agents as usual.

The daily fetch was failing with `HTTP Error 429: Too Many Requests`
partway through pagination: `list_all_recordings` walked pages back to
back with no delay and `_get` raised on the first error response, so a
single rate-limited page aborted the whole run.

- Add `_request`, a shared GET helper that retries 429s and transient
  5xx/network errors with exponential backoff, honoring `Retry-After`
  when the API sends it.
- Route `_get` and `get_transcript_text` through the new helper so
  transcript fetches get the same treatment.
- Pause briefly between paginated list requests and between per-recording
  hydration requests, tunable via `GRAINIAC_PAGE_DELAY`.

Co-Authored-By: Warp <agent@warp.dev>

dplakon commented Aug 20, 2026

Copy link
Copy Markdown
Author

This PR was generated with Warp.

Comment @warp-agent on this PR to send it follow-up work.

View run View conversation

@warp-factories

Copy link
Copy Markdown

Your Warp account is not a member of any team with access to this repository.

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