I have used Celery Beat for scheduled tasks for a long time. It is simple and useful, but it has one persistent problem: if multiple Beat instances run at the same time, tasks get scheduled more than once.
We previously relied on uWSGI legion mode to make sure only one Beat instance was active at a time, but that depends on having a reliable network connection. Recently I ran into a case where the network between two Beat nodes could be unstable, so uWSGI legion no longer felt safe enough. That led me to look for a way to make Celery Beat enter a “standby” mode: the service stays up, but it stops generating scheduled tasks.
After reading the Celery Beat source code, I found that the celery CLI eventually calls the start method on the Service class from celery.beat. So the easiest approach seemed to be patching that method.
Here is a simple monkey patch:
1 | import os |
A quick explanation:
- This example checks whether
/tmp/standby.flagexists. - If the file exists, Beat is considered to be in standby mode.
- Inside the main loop, Beat checks for that file before scheduling tasks.
- If the file is present, it sleeps for 5 seconds and checks again.
To use it, just apply the patch at your startup entry point:
1 | from celery.beat import Service |
After that, once Celery Beat has started, you can run touch /tmp/standby.flag to put it into standby mode. It will stop generating scheduled tasks. Remove the file, wait a few seconds, and Beat will resume normal scheduling.