Deferrable and Async Operators in Airflow
Architecture Diagram
Formal Definitions
Detailed Explanation
The Problem with Blocking Operators
When a traditional operator waits for an external event (like an API response or file availability), it holds a worker slot the entire time. This wastes resources because the worker is doing nothing but polling.
Key Insight: A blocking sensor polling every 30 seconds for 1 hour uses only 0.1% of its time productively â the other 99.9% is wasted polling.
How Deferrable Operators Solve This
| Aspect | Blocking Operator | Deferrable Operator |
|---|---|---|
| Worker Slot | Held during entire wait | Released immediately |
| Memory Usage | ~50-200MB per task | ~1KB per trigger |
| Concurrency | Limited by executor slots | Limited by triggerer capacity |
| Resource Efficiency | Low | High |
Why Deferrable Operators?
Traditional blocking operators hold a worker slot while waiting for external conditions. For long-running operations like API callbacks, database queries, or cloud job completions, this wastes valuable executor resources. Deferrable operators release the worker slot immediately and delegate the wait to the lightweight triggerer process.
For a blocking sensor polling every 30 seconds for 1 hour: (nearly all time is wasted polling). A deferrable equivalent achieves since the worker slot is released immediately.
Creating a Deferrable Operator
HTTP Polling Trigger
Triggerer Configuration
Key Concepts Table
| Component | Purpose | Resource Impact | Scaling |
|---|---|---|---|
| Deferrable Operator | Releases worker slot on defer | Minimal worker usage | Independent of worker count |
| Trigger Object | Async event definition | Near-zero in memory | Serialized to DB |
| Triggerer Process | Executes async triggers | Single process, many coroutines | Scale by capacity config |
| Trigger Callback | Requeues completed task | Metadata DB write | Scales with DB connections |
| BaseTrigger | Base class for triggers | N/A | N/A |
Comparison: Blocking vs Deferrable
| Metric | Blocking Operator | Deferrable Operator |
|---|---|---|
| Worker slot held | Entire duration | Only during execute() |
| Memory per wait | ~50-200MB (worker process) | ~1KB (trigger object) |
| Concurrency | Limited by executor slots | Limited by triggerer capacity |
| Latency on completion | Poll interval | Seconds (triggerer heartbeat) |
| Implementation complexity | Simple | Moderate |
| Best for | Short waits (<5 min) | Long waits (>5 min) |
Code Examples
Custom Trigger with Multiple Conditions
Deferrable Sensor Pattern
Performance Metrics
| Metric | Blocking | Deferrable | Improvement |
|---|---|---|---|
| Worker slot time (1hr wait) | 3600s | ~0.1s | 36000x |
| Memory per waiting task | ~100MB | ~1KB | 100000x |
| Max concurrent waits (16 slots) | 16 | 1000+ | 62x+ |
| Task startup overhead | Worker process | Trigger coroutine | Negligible |
Best Practices
Implementation Guidelines
- Use for long waits: Deferrable operators shine when tasks wait >5 minutes for external events.
- Implement serialize(): Always implement
serialize()on triggers for persistence across triggerer restarts. - Handle timeouts: Set
execution_timeouton defer calls to prevent infinite waits. - Use async libraries: Leverage
aiohttp,httpx, oraiobotocorefor non-blocking I/O in triggers.
Operational Guidelines
- Monitor triggerer capacity: Track
triggers.runningandtriggers.queuedmetrics. - Fail gracefully: Handle trigger errors by yielding
TriggerEvent({'status': 'error'}). - Avoid blocking in triggers: Never use
time.sleep()or synchronous I/O in triggerrun()methods. - Test triggers independently: Mock the async loop and verify trigger serialization.
When to Use Deferrable Operators
| Scenario | Use Deferrable? | Reason |
|---|---|---|
| API polling (>5 min) | Yes | Saves worker resources |
| Database queries (<1 min) | No | Overhead not justified |
| File existence checks | Yes | Can wait indefinitely |
| Cloud job monitoring | Yes | Jobs can run for hours |
| Quick HTTP calls (<30s) | No | Simpler to use blocking |
See Also
- Sensors and Operators â Blocking sensors and poke modes
- Scheduling and Triggers â Timetables and scheduling patterns
- Operators and Hooks â Operator lifecycle and hook architecture
- Executors Comparison â Executor selection and resource management