0

I'm building an application in which some tasks are scheduled by using CRON like jobs (with celery). Through an interface, jobs are saved as celery jobs with django-celery-beat package.

For that, the schedule the users want is translated into a CRON expression such as 30 9 * * 1 (Every Monday at 9:30). It works well. But the celery backend as well as the database are working in UTC timezone. While end users of my application way work from a different timezone.

So if a user is working in UTC+1, and he wants the job to be run at 9:30 each Monday, it's not 30 9 * * 1 that will have to be used but 30 8 * * 1 instead.

This use case is kinda easy to solve but what if I want it to be run at 00:00 on each Monday ? It means that I'll have to go a day backwards, so Sunday at 23:00 which would lead to 0 23 * * 0. And the same behavior for every possible timezone other than UTC.

Is there an easy way to do so ?

Also I'm worryied about DST...

Thanks in advance !

lbris
  • 1,068
  • 11
  • 34
  • _“I'm building an application in which some tasks are scheduled by using CRON jobs.”_ And that is a big mistake. – Andrej Podzimek Dec 26 '22 at 10:33
  • @AndrejPodzimek and why that ? – lbris Dec 26 '22 at 15:52
  • Because `cron` is an outdated and flawed, inherently unreliable technology. Today’s standards are higher: high timing precision, task and timer state bookkeeping (also across multiple system uptimes), automatic output logging and log management, dependency tracking (and resolution) among tasks and services, full task lifecycle management and failure + retry handling, proper security hardening with ample of sandboxing options tailored to each task, etc. `systemd`’s `.timer` units provide _all_ of that, whereas `cron` has _none_ of that and is therefore better avoided. – Andrej Podzimek Dec 26 '22 at 17:17
  • @AndrejPodzimek If you read correctly, it is said I use celery, which is well known in the python ecosystem. The cron expressions are just used in django-celery-beat so that celery knows what schedule to apply. And instead of just saying "this is bad", you could elaborate and provide a proper answer. – lbris Dec 27 '22 at 00:02

1 Answers1

0

There's two things here.

  • first is changing the hour value, which can easily be achieved via:
    # Hour difference
    h_diff = 1
    # Original Crontab
    cron = "30 8 * * 1"
    
    # Fixing hour
    cron_list = cron.split(" ")
    h_val = cron_list[1]
    corrected_hour = (h_val - h_diff) % 24
    cron_list[1] = corrected_hour
    
    # Recreating Crontab
    new_crontab = " ".join(cron_list)

You should convert to UTC and stay there unless printing for users. However you might have to redefine your crons daily to be able to catch DST changes.

scr
  • 853
  • 1
  • 2
  • 14
  • The day of the week may have to be changed too, if you set that it is supposed to be run on Monday at midnight from UTC+1 `0 0 * * 1`, it'll have to be done on Sunday so `0 23 * * 0`. I saw a package called `local-crontab` https://github.com/Sonic0/local-crontab, available on PyPI but it generates a set on CRON expressions during the conversion (because of DST). I don't know if it can be done differently (with a single one). Also, the original CRON expression may have multiple days like so : `30 9 * * 1,2,3`. – lbris Dec 27 '22 at 08:21