Bounded concurrency and a timeout with asyncio
Change Semaphore(2) to Semaphore(1) and Semaphore(3) and watch the start/end order in the log change. Results always keep the order of the calls.
The questions that separate someone who has written scripts from someone who has run Python services: packaging and environments, async versus threads versus processes, finding memory and speed problems, testing strategy, typing, and API design.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 6 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write an async function fetch_all(names, limit) that fakes a 0.01-second call per name, runs at most limit at a time, and returns the results in input order.
Write a FakeClock and a Cache class whose entries expire after ttl seconds, using the injected clock. Show an entry expiring without sleeping.
Write a function retry(fn, attempts) that calls fn() up to attempts times, re-raising the last error if all fail.
Explain it without notes
How do you make a Python project reproducible across a laptop, CI and a container?
When do you pick asyncio, threads or processes? Give one example of each.
A Python service's memory keeps growing. How do you investigate?
How do you test code that depends on the current time or a remote API?
What do you consider when designing the interface of a service that calls a slow model API on behalf of users?
Where do configuration and secrets (API keys, passwords) belong in a Python service, and where must they never go?
What is the difference between a mock and a fake, and what does the rule "patch where it is used" mean?
Expected output
results keep call order: ['A', 'B', 'C']
log: ['start a', 'start b', 'end b', 'start c', 'end c', 'end a']
timed out and cancelled the slow call