Matthew Eng
11/12/2025, 4:51 PMMarvin
11/12/2025, 4:51 PMcheck_cli_command
📊 Tools used:
• check_cli_command (4x)
• research_prefect_topic (1x)Matthew Eng
11/12/2025, 7:41 PMMarvin
11/12/2025, 7:41 PMMarvin
11/12/2025, 7:41 PMMatthew Eng
11/12/2025, 7:41 PMMarvin
11/12/2025, 7:41 PMMarvin
11/12/2025, 7:45 PMrun_deployment or API), they will wait for a worker slot. If your worker concurrency is 4 and it’s also running the parent flow, the remaining child runs can sit Pending until there’s capacity.
- Fixes:
- Increase worker concurrency/capacity for the pool
- Run child work in a separate pool from the parent
- Or run spiders as tasks/subflows within the same process instead of separate flow runs
- Docs: Work pools
- Task runner concurrency vs orchestration limits
- If you’re relying on ConcurrentTaskRunner(max_workers=4), it should continue scheduling more work as threads free up. If tasks still hang, it’s usually an orchestrator-level limit (tags/global) or you’re awaiting too early (see next bullet).
- Docs: Task runners
- Awaiting too early inside the loop
- If your code awaits each spider immediately in the loop, you’ll effectively serialize after the first batch. Prefer submitting all, then waiting:
- Example pattern:
from prefect import flow, task
from prefect.task_runners import ConcurrentTaskRunner
@task(tags=["spider"])
def run_spider(name):
...
@flow(task_runner=ConcurrentTaskRunner(max_workers=4))
def run_all(spiders: list[str]):
futures = [run_spider.submit(s) for s in spiders]
return [f.result() for f in futures]
- If you’re using tag-based concurrency for “spider”, set that limit in UI to 4 and Prefect will keep backfilling as slots free.
- Rate limits vs fixed concurrency
- If you used a rate limit (global or tag-based) rather than a simple concurrency limit, new tasks may remain scheduled/pending until the refill rate allows more. Check the state message for “waiting for rate limit” language.
What would help me pinpoint it
- Are the spiders tasks in one flow, or separate flow runs kicked off from the parent (e.g., `run_deployment`/API)?
- How did you set “concurrency 4”? Task runner max_workers, tag-based concurrency, or worker/pool capacity?
- A small code snippet of how you launch the spiders (loop, submit/map, await).
- From the UI, what does a Pending spider’s state details say? (“Awaiting concurrency slot”, “Scheduled by …”, etc.)
If you can share those details, I can give an exact fix. In the meantime, check the Pending task’s state message and the Concurrency Limits page — they usually reveal whether it’s a tag/global limit or worker capacity.