Cron jobs are the duct tape of backend automation. Run this script every hour. Check for new data every five minutes. Send reports at midnight. It works until it doesn’t — when the script takes longer than the interval, when two instances run simultaneously, when a failure at 3 AM goes unnoticed until morning.
Event-driven architectures solve these problems by processing work as it arrives, not on a schedule. In Python, the ecosystem has matured enough that event-driven patterns are accessible without the complexity of Kafka or RabbitMQ.
Celery: Still the Workhorse
Celery remains the most popular task queue for Python in 2026. It’s battle-tested, well-documented, and integrates with Django and FastAPI through mature packages. Workers process tasks from Redis or RabbitMQ queues, with built-in retries, rate limiting, and result storage.
The key pattern: replace cron jobs with Celery beat for periodic scheduling and Celery tasks for event-driven processing. Instead of a cron job that polls a database every five minutes, an application event triggers a Celery task immediately. Instead of a nightly batch job that processes yesterday’s data, data arrives as events and gets processed in near real-time.
Redis Streams: The Lightweight Alternative
For simpler use cases, Redis Streams provides event-driven processing without the operational overhead of a dedicated task queue. Redis Streams are append-only logs that support consumer groups for load-balanced processing. A Python producer adds events to a stream. One or more consumers read and process events.
The advantage: if you’re already using Redis for caching or session storage, you get a message queue without adding infrastructure. The limitation: Redis Streams don’t have the sophisticated retry, routing, and monitoring features of Celery or dedicated message brokers.
When to Adopt Event-Driven Patterns
Event-driven architecture adds complexity. You now have producers, consumers, queues, and dead-letter handling to manage. The operational overhead is higher than a cron job. Adopt event-driven patterns when the business value justifies the complexity: when you need lower latency than a cron schedule, when you need guaranteed processing with retries, or when you need to scale processing independently of your web application.
For a weekly report that no one looks at until Monday morning, a cron job is fine. For processing user uploads that should complete in seconds, event-driven is the right choice.
The Migration Path
Start by identifying the cron job that causes the most operational pain — the one that fails silently, runs too long, or processes stale data. Replace it with a Celery task triggered by an application event. Run both in parallel for a week to validate correctness. Then remove the cron job. Repeat for the next pain point.
Discussion
Leave a comment
No comments yet
Be the first to start the conversation.