Polling a Sume job for 20 minutes: 600 fixed reads or 44 backed off
Counting reads for a 20-minute Sume job poll: fixed 2 s versus a 1 s schedule doubling to 30 s. Arithmetic you can run, and why the server hint still wins.

Over a 20 minute window, polling every 2 seconds is 600 reads, while a schedule that starts at 1 second and doubles up to a 30 second cap is 44. Sume's docs recommend a poll interval of 2 seconds, and the status response carries next_poll_after_seconds, so the right loop honors that hint and uses backoff only as a floor for when you do not have one.
The numbers below are plain arithmetic from the script shown, not a measurement of any service.
The arithmetic
The script counts how many reads fit in a window for each policy.
def reads(window_s: int, first=1, cap=30) -> int:
t = n = 0
delay = first
while t < window_s:
t += delay
n += 1
delay = min(delay * 2, cap)
return n
for minutes in (2, 10, 20):
w = minutes * 60
print(minutes, "min | every 2 s:", w // 2, "| 1 s doubling to 30 s:", reads(w))What it prints
These are the outputs of the script for 2, 10 and 20 minutes.
| Window | Every 2 s | 1 s doubling to 30 s |
|---|---|---|
| 2 minutes | 60 | 8 |
| 10 minutes | 300 | 24 |
| 20 minutes | 600 | 44 |
Which one to use
The docs recommend roughly a 20 minute client deadline for video, so the last row is the realistic worst case for one job. Multiply by the number of jobs you run at once and the difference is large for a batch.
Neither schedule should override the server. The status endpoint returns next_poll_after_seconds (2 by default, capped at 30 for delayed jobs, null once the job is terminal), and the recommended interval is 2 seconds. A loop that sleeps for the hint when present, and otherwise doubles up to 30, gets the benefit of both.
A third option is to follow the status response itself. It reports next_poll_after_seconds, which is 2 by default and is capped at 30 for delayed jobs, and it is null once the job has ended. A loop that sleeps for that value, falls back to your own doubling schedule when the field is missing, and adds a little random jitter so that many jobs do not poll in lockstep, is both polite and responsive. Your rate limits still apply to every read, and a 429 should be treated as a signal to slow down and honor the retry-after header.
Tradeoffs
Backing off makes you slower to notice completion, by up to the cap. For a short clip that finishes in under a minute, a slow schedule wastes more time than it saves reads. If latency matters more than read count, a webhook avoids the question entirely; keep a slow poll as a backstop.
Sources
Related posts
More in Developers
- Poll Sume status in a loop, read the full job once at the end
Poll the lightweight status for progress and read GET /v1/jobs/{id} once at a terminal state to get the error. What next_action tells you and the 409 on result.
- Poll many transcription jobs without a 429: next_poll_after_seconds
Poll Sume job status with the next_poll_after_seconds the API sends, back off on 429 with retry-after, and stop on a terminal status.
- Clicks or gaps when joining TTS MP3 clips: render WAV, join once
Joined MP3 voiceover clips can gap or click. Sume's Timeline audio docs explain why: MP3 adds priming padding at each edge. Keep WAV until the last step.
- Postgres SKIP LOCKED poll table for AI video jobs with next_poll_at
Track Sume video jobs in one Postgres table with next_poll_at, claim due rows with FOR UPDATE SKIP LOCKED and reschedule from next_poll_after_seconds.
Written by Sume