All three run BookNest at 02:00 UTC for the previous day, and all three can start a run when the order service says its export is ready. The mechanisms differ:
| Trigger | Airflow 3 129 | Dagster 177,056 | Prefect 3 74,615 |
|---|---|---|---|
| Clock | Timetable (cron, data interval) | Schedule on a partitioned job | Deployment schedule |
| Upstream data | Asset schedule | Automation conditions | Automation on events |
| External signal | Asset watcher (triggerer) | Sensor (daemon polls) | Event trigger (pushed) |
| Backfill | Scheduler-managed backfill | Partition backfill | Runs with parameters |
Airflow's watcher (Event-Driven Scheduling) and Dagster's sensor (Daemon, Sensors, Schedules) both look for the marker; Prefect lets the producer tell it. The deployment trigger of Deployments and Work Pools fired on a custom event that emit.py sent for 30 June with emit_event(event="booknest.export.ready", payload={"ds": "2026-06-30"}, ...), read back from Prefect's events and flow_run tables:
02:17:31|booknest.export.ready 02:17:32|prefect.flow-run.Scheduled 02:17:45|prefect.flow-run.Running 02:17:53|prefect.flow-run.Completed crafty-cuckoo|02:17:32|AUTOMATION|daily__automation_1
The run existed one second after the event, with ds taken from its payload; the remaining 13 seconds were the worker's 10-second poll and process start-up. Polling costs a little CPU on every tick; pushing needs the producer to know the orchestrator's API. For data that changes many times a minute, none of these fit: stream it (Apache Kafka and Managed Cloud Kafka) or capture changes (CDC with Debezium 3.x).