How can I notify an async routine from a sync routine?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
A synchronous routine cannot await, so it cannot notify an async routine by directly calling async code and expecting a result immediately. The usual solution is to hand work or a signal to the event loop through a thread-safe mechanism such as an event, queue, or scheduled coroutine.
Use the Event Loop as the Handoff Point
In Python asyncio, the event loop owns async tasks. If synchronous code needs to notify an async routine, the safe design is:
- async code waits on an event or queue
- sync code signals that event through the loop
- the loop wakes the async task
Here is a complete example using asyncio.Event:
The important call is loop.call_soon_threadsafe(event.set). That schedules the notification safely onto the event loop from synchronous code running in another thread.
Use run_coroutine_threadsafe When the Sync Side Must Trigger Async Work
Sometimes the synchronous routine does not just want to set a flag. It wants to launch a coroutine. In that case, schedule the coroutine onto the loop explicitly:
This is useful when the sync side wants to submit real async work rather than just flip a shared event.
Choose the Right Notification Primitive
The best primitive depends on the shape of the communication:
- use
Eventfor a simple signal - use
Queuewhen data must be passed - use
run_coroutine_threadsafewhen the sync side needs to schedule a coroutine directly
The async routine should wait in an async-friendly way. The sync side should never try to manipulate async objects directly without going through the loop's thread-safe entry points.
Common Pitfalls
The biggest mistake is calling async functions from synchronous code without an event-loop handoff. Creating a coroutine object is not the same as running it.
Another issue is touching asyncio primitives from the wrong thread. If synchronous code runs outside the loop thread, use call_soon_threadsafe or a similar safe bridge.
Developers also sometimes block the event loop while waiting for the sync side to finish. That defeats the purpose of async coordination and can freeze the whole system.
Finally, if the sync side needs a response, design that explicitly. Notification is one-way by default. Request-response usually needs a future, queue, or another callback path.
Summary
- Sync code cannot notify async code by
awaiting directly. - Use the event loop as the handoff boundary.
- '
loop.call_soon_threadsafeis the standard way to signal async primitives from sync code in another thread.' - '
asyncio.run_coroutine_threadsafeis useful when sync code must schedule a coroutine.' - Pick an
Event,Queue, or scheduled coroutine based on whether you need a signal, data, or executable async work. - A thread-safe handoff is more reliable than shared mutable flags polled from async code.
- If sync code needs a result back, pair the notification with a future or queue.
- Keep the event loop free to process the notification promptly.
- Direct cross-thread access to asyncio objects is a correctness bug.

