Polling a 5-minute video: 30 s is 10 reads, 2 s is 150 on Sume

How often to poll a Sume video job: read counts for a 300 s job at 30 s and 2 s, and an asyncio loop that obeys next_poll_after_seconds.

4 min readSume
All posts

Poll as often as the response tells you to. When next_poll_after_seconds is present, obey it; when it is not, back off. For a video that happens to take 300 seconds, a fixed 30-second interval costs 10 status reads and the SDK's 2-second floor costs 150. Both are far below the read budget, so the interval is a latency choice, not a limit problem.

Two documented defaults

Sume's video guide suggests a moderate interval such as 30 seconds, and notes that generation usually takes from 30 seconds to several minutes. The TypeScript SDK waitForJob uses a 2-second poll interval as a floor, a 20-minute default timeout, and lets a longer next_poll_after_seconds win.

Status reads for an example 300 s job (arithmetic from Sume docs defaults, read 2026-10-09)
IntervalReads for 300 sReads per minute for one jobShare of a Free key's 4,800 reads per minute
30 s1020.04%
2 s150300.63%
2 s, all 6 accepted Free jobs at once9001803.75%

What the loop should do

Stop on terminal: true, not on a guess. Honor next_poll_after_seconds. Keep your own deadline, because the server-side sync wait is capped at 30 seconds and says nothing about job duration. A client timeout does not cancel the job, and it still bills. Store the job id so you can read it again.

import asyncio
import json
import os
import time
import urllib.request
HEADERS = {"Authorization": f"Bearer {os.environ.get('SUME_API_KEY', '')}"}
def get(path: str) -> dict:
    req = urllib.request.Request("https://api.sume.com/v1" + path, headers=HEADERS)
    with urllib.request.urlopen(req, timeout=20) as resp:
        body = json.load(resp)
    return body.get("data", body)

async def wait(job_id: str, deadline_s: float = 1200) -> dict:
    end = time.monotonic() + deadline_s
    reads, delay = 0, 2.0
    while time.monotonic() < end:
        status = await asyncio.to_thread(get, f"/jobs/{job_id}/status")
        reads += 1
        if status.get("terminal"):
            print("status reads:", reads)
            return status
        delay = float(status.get("next_poll_after_seconds") or min(delay * 2, 30))
        await asyncio.sleep(delay)
    raise TimeoutError(job_id)  # the job keeps running and billing
async def main() -> None:
    print(await wait(os.environ["JOB_ID"]))

asyncio.run(main())

Reads have their own budget

Reads and writes are separate buckets, and reads get 40 times the plan's write number. On Free that is 4,800 reads per minute. A poll loop cannot cause a 429 on your submits. Reading ratelimit-remaining and retry-after is still better than counting calls yourself.

If many clients start at once, add jitter. The SDK helpers do, because without it clients that start together stay in phase and hit the ceiling as a group.

Choosing an interval

Use the server's hint. The status response carries next_poll_after_seconds, and following it keeps reads low while still catching completion promptly. The read bucket is large, 40 times the write limit, so polling rarely causes a 429 by itself, but a fleet of pollers on one key can add up.

For long jobs, prefer a webhook plus one backup poll. If a job takes 300 seconds, a 30-second interval costs about 10 reads, while a 2-second interval costs 150 for the same information.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume