Runnable example

Async batch fetcher with bounded concurrency

Implement a resilient async batcher with Semaphore concurrency control, exponential backoff for transient failures, and per-item error isolation.

Intermediate10–15 minAutomationPython 3.12+ · Standard library only

The problem

Unbounded asyncio.gather concurrency leads to socket exhaustion, 429 rate limiting, and cascading server failures. A production batch fetcher must bound concurrency, retry transient failures, fail fast on permanent errors, and keep one bad item from crashing the batch.

The contract

  1. Bound concurrent requests with asyncio.Semaphore instead of unbounded gather.
  2. Retry transient failures — 429, 503, timeouts — with bounded exponential backoff.
  3. Fail fast on permanent errors such as 400 and 404 without retrying them.
  4. Isolate per-item failures and return structured success and error records.

Verify it locally

From the root of the FlyPython repository, reproduce the broken starter first, then verify the reviewed solution:

python examples/async-fetcher/verify.py starter --expect-failure
python examples/async-fetcher/verify.py solution

Hand it to a coding agent

  1. Clone the repository and reproduce the starter failure with the command above.
  2. Give the task contract ↗ to your coding agent and allow changes only in starter/fetcher.py.
  3. Run python examples/async-fetcher/verify.py starter and treat any failure as unfinished work.
  4. Compare the patch with the reference solution ↗ — the goal is the same contract with a small, readable diff, not identical syntax.

Keep going

Where this example sits in the roadmap.

Reviewed 2026-09-02 · Repository content version 1. Continue with the related learning path, the repository directory, or the MCP migration guide for the specification background.