5

I am building a Django app that uses APScheduler to send out a daily email at a scheduled time each day. Recently the decision was made to bump up the number of instances to two in order to always have something running in case one of the instances crashes. The problem I am now facing is how to prevent the daily email from being sent out by both instances. I've considered having it set some sort of flag on the database (Postgres) so the other instance knows not to send, but I think this method would create race conditions--the first instance wouldn't set the flag in time for the second instance to see or some similar scenario. Has anybody come up against this problem and how did you resolve it?

EDIT:

def start(): scheduler = BackgroundScheduler() scheduler.add_job(send_daily_emails, 'cron', hour=11) scheduler.start()

So this is run when my app initializes--this creates a background scheduler that runs the send_daily_emails function at 11am each morning. The send_daily_emails function is exactly that--all it does is send a couple of emails. My problem is that if there are two instances of the app running, two separate background schedulers will be created and thus the emails will be sent twice each day instead of once.

jtbrubak
  • 51
  • 3
  • Could you add some code or at least some errors or screenshots of your issue? – Vendetta Feb 03 '20 at 17:03
  • Well, it's not an issue or error yet. It'll become an issue once the number of instances is bumped up to 2. I was looking for kind of a high-level solution and not necessarily something specific to my code, but I'll add a little something. – jtbrubak Feb 03 '20 at 17:38
  • Could you possibly forcibly produce that error and post it? – Vendetta Feb 03 '20 at 18:58
  • I'm using `django-crontab` and facing similar issue. did you had any luck with this? – Ashwin Dec 07 '22 at 06:46

3 Answers3

2

You can use your proposed database solution with select_for_update

Nader Alexan
  • 2,127
  • 22
  • 36
0

If you're using celery, why not use celery-beat + django-celery-beat?

2ps
  • 15,099
  • 2
  • 27
  • 47
0

You can use something like the following. Note the max_instances param.

def start():
    scheduler = BackgroundScheduler()
    scheduler.add_job(send_daily_emails, trigger='cron', hour='23', max_instances=1)
    scheduler.start()
Rajesh Panda
  • 636
  • 6
  • 10