roshan Kumar
02/15/2026, 3:52 PMMarvin
02/15/2026, 3:52 PMMarvin
02/15/2026, 3:55 PMroshan Kumar
02/15/2026, 3:58 PMMarvin
02/15/2026, 3:58 PMMarvin
02/15/2026, 4:00 PMroshan Kumar
02/15/2026, 4:07 PMMarvin
02/15/2026, 4:07 PMMarvin
02/15/2026, 4:09 PMfrom prefect import flow
from prefect.flow_runs import pause_flow_run
@flow
async def poll_api_then_continue():
# do your API call here
# ... call API, get a job_id, etc.
# Don't sleep — pause instead to release the worker
await pause_flow_run(timeout=180) # 3 minutes max wait
# After resume (manually or via automation/webhook), continue
# ... check API for completion, finish up
If you need to capture structured input on resume (e.g., webhook payload or approval), you can:
from prefect.flow_runs import pause_flow_run
from prefect.input import RunInput
class DoneSignal(RunInput):
job_id: str
await pause_flow_run(wait_for_input=DoneSignal, timeout=600)
Then resume it with:
from prefect.client import get_client
from uuid import UUID
async with get_client() as client:
await client.resume_flow_run(
flow_run_id=UUID("..."),
run_input={"job_id": "123"}
)
Notes:
- Subflows can pause, but suspend_flow_run is only for top‑level flows with deployments and persisted results.
- Awaiting/paused states don’t consume worker slots; the slot is reacquired when the run resumes and becomes PENDING/RUNNING again.
If you’d like, share how you plan to trigger the resume (manual click, webhook, automation), and I can tailor the pattern.roshan Kumar
02/15/2026, 4:13 PMMarvin
02/15/2026, 4:13 PMMarvin
02/15/2026, 4:14 PMrequests.get(..., timeout=120) that blocks for ~2 minutes), then yes — that flow run will hold a worker slot the entire time it’s waiting. There’s no way to “free” the slot in the middle of a blocking call.
Options to avoid tying up the worker:
- Restructure to “submit + wait” and pause in between:
- Kick off the job (or a short request), then pause_flow_run(timeout=...) and resume later (manually, via webhook, or automation), then check status and continue.
- Works in sync flows; pause_flow_run is synchronous.
from prefect import flow
from prefect.flow_runs import pause_flow_run
@flow
def api_job():
job_id = start_job() # returns quickly with an id
pause_flow_run(timeout=180) # frees the worker slot for up to 3 minutes
status = check_status(job_id) # after resume
return status
- For longer/safer handoffs, use suspend (requires a deployment and persisted results):
from prefect import flow
from prefect.flow_runs import suspend_flow_run
@flow(persist_result=True)
def api_job():
job_id = start_job()
suspend_flow_run(timeout=180) # frees worker and reschedules on resume
status = check_status(job_id)
return status
- If the API absolutely forces a single blocking call you can’t break up:
- You will use a worker slot for the duration. Mitigations:
- Run these flows in a dedicated work pool (so they don’t starve other work) and/or increase worker concurrency for that pool.
- Offload the blocking call to an external service (e.g., serverless/job queue) and have your flow pause and wait for a callback to resume.
- Polling alternative: lower the HTTP timeout (e.g., 10–20s), loop with pause_flow_run between polls so each wait frees the worker.
If you can share whether your API supports “submit + status” or a webhook callback, I can sketch the exact pause/resume or automation wiring.