Projects: Async Python¶
Projects are the best way to cement async Python skills. They are ordered by difficulty from beginner to expert. Each project includes a clear goal, required modules, and acceptance criteria. Do not copy-paste solutions from the internet — the struggle is the learning.
Beginner Projects¶
Project 1: Async File Reader and Word Counter¶
Difficulty: Beginner Requires: Module 01, Module 04 Estimated Time: 2–3 hours
Goal: Write a command-line tool that reads multiple text files concurrently using
aiofiles, counts word frequencies in each file, and prints a combined summary.
Acceptance Criteria:
- Reads 3+ files concurrently (not sequentially)
- Uses asyncio.gather() to parallelize file reads
- Counts word frequency and prints the top 10 words
- Handles the case where a file does not exist gracefully
Stretch Goal: Accept a directory path and process all .txt files in it.
Project 2: Async URL Health Checker¶
Difficulty: Beginner Requires: Module 01, Module 03, Module 04 Estimated Time: 3–4 hours
Goal: Build a tool that takes a list of URLs and checks whether each returns HTTP 200, how long each takes to respond, and reports any that are slow or unreachable.
Acceptance Criteria:
- Checks all URLs concurrently using aiohttp
- Reports status code and response time for each URL
- Flags URLs that time out or return non-200 status
- Respects a configurable concurrency limit (e.g., max 10 requests at a time)
using asyncio.Semaphore
Stretch Goal: Re-check failed URLs with exponential backoff retry.
Intermediate Projects¶
Project 3: Async News Aggregator¶
Difficulty: Intermediate Requires: Modules 01–05 Estimated Time: 6–8 hours
Goal: Build an async program that fetches headlines from 3–5 public RSS/JSON news APIs concurrently, deduplicates them by title, and writes the combined list to a file sorted by publication date.
Acceptance Criteria:
- Fetches from at least 3 sources concurrently
- Deduplicates stories by normalized title
- Handles network errors on individual sources without failing the whole aggregation
- Writes output to a JSON file with timestamps
- Uses asyncio.Lock to protect shared data structures during concurrent writes
Stretch Goal: Run the aggregation on a schedule (every 15 minutes) without using
time.sleep().
Project 4: Async Rate-Limited API Client¶
Difficulty: Intermediate Requires: Modules 03–05, Module 07 Estimated Time: 6–10 hours
Goal: Write an async client for a public API (e.g., GitHub API, a weather API) that respects rate limits, retries on transient errors, and processes paginated results concurrently across multiple resource types.
Acceptance Criteria:
- Implements a RateLimiter class using asyncio.Semaphore
- Handles HTTP 429 (Too Many Requests) with a proper delay
- Fetches multiple pages of results concurrently within rate limits
- Implements retry with exponential backoff for 5xx errors
- Has typed response models (dataclasses or Pydantic)
Stretch Goal: Add a circuit breaker that stops retrying after N consecutive failures.
Advanced Projects¶
Project 5: Async Job Queue System¶
Difficulty: Advanced Requires: Modules 03–06, Module 08, Module 09 Estimated Time: 12–16 hours
Goal: Build a simple in-process async job queue with workers, priority levels, job results, and error handling. Similar in spirit to Celery but entirely in-process using asyncio primitives.
Acceptance Criteria:
- JobQueue class accepts submitted coroutine functions as jobs
- Configurable number of worker tasks consuming from the queue
- Jobs have priority levels (high/medium/low)
- Job results (success or exception) are stored and retrievable by job ID
- Workers handle exceptions in individual jobs without stopping
- Graceful shutdown: drains the queue before stopping workers
- Full test suite using pytest-asyncio
Stretch Goal: Add job timeouts using asyncio.wait_for().
Expert Projects¶
Project 6: Async Data Ingestion Service¶
Difficulty: Expert Requires: All modules (01–10) Estimated Time: 20–30 hours
Goal: Build a production-grade async data ingestion service that: polls multiple external APIs concurrently, validates and transforms incoming data, writes to a PostgreSQL database using asyncpg, exposes a health check endpoint, and shuts down gracefully on SIGTERM.
Acceptance Criteria:
- At least 3 concurrent API pollers with configurable intervals
- Input validation with error logging (invalid records skipped, not crashed)
- Async writes to PostgreSQL using asyncpg connection pool
- /health endpoint that reports worker status and database connectivity
- Graceful shutdown: flushes pending writes and cancels pollers on SIGTERM
- Structured logging with per-request trace IDs
- Test suite covering: pollers (mocked HTTP), DB writer (mocked pool), and shutdown behavior
Getting Unstuck:
Hint: High-level architecture
Consider three layers: 1. **Pollers** — one coroutine per API, running in a loop, putting records into an `asyncio.Queue` 2. **Writers** — N worker coroutines consuming from the queue and batching inserts 3. **Coordinator** — a top-level `TaskGroup` that owns all pollers and writers, and handles cancellation on shutdown The queue provides natural backpressure: if writers are slow, pollers will block on `queue.put()`.Hint: Graceful shutdown pattern
import asyncio
import signal
async def main():
loop = asyncio.get_running_loop()
stop = asyncio.Event()
def _on_sigterm():
stop.set()
loop.add_signal_handler(signal.SIGTERM, _on_sigterm)
async with asyncio.TaskGroup() as tg:
tg.create_task(run_pollers(stop))
tg.create_task(run_writers(stop))
await stop.wait()
# TaskGroup will wait for all tasks to finish before exiting