Package: django-cronman
django-cronmanOverviewDjango app to define and manage periodic tasks at Python level.Installationdjango-cronmancan be installed directly from PyPI usingpip:pipinstalldjango-cronmanYou can also install it with additional dependencies to be able to use Cron Remote Manager.pipinstalldjango-cronman[redis]Define a new cron jobCron job definition is inspired by Django Admin configuration. To add a new job, you have to createcron_job.pyfile inside an app, createBaseCronJobsubclass inside and register it:fromcronman.jobimportBaseCronJob,cron_job_registryclassHelloWorld(BaseCronJob):"""Demo Cron Job class"""defrun(self):"""Main logic"""passcron_job_registry.register(HelloWorld)Cron job classes are registered (and referred to) by name, which may be customized on registration:cron_job_registry.register(HelloWorld,name='Hello')It's also possible to retrieve or unregister a class (e.g. while testing):cron_job_registry.get('HelloWorld')cron_job_registry.unregister('HelloWorld')If there is more than 1 cron job in given app, it's recommended to create a package instead of singlecron_jobsmodule, create one submodule per class and do the imports and registration in package's__init__.py.Configure cron jobsTo ensure that a cron job is executed periodically, you have add an entry toCRON_JOBS:CRON_JOBS=(...# (<time spec>, <job spec>)# 'HelloWorld' will be executed a 5:15AM every day:('   15   5   *   *   *','HelloWorld'),)SetCRONMAN_JOBS_MODULEto the dotted path name of the module where cron jobs are specified. Remember, this module MUST have aCRON_JOBSattribute.CRONMAN_JOBS_MODULEisNoneby default. For example:# settings_local.pyCRONMAN_JOBS_MODULE='app.cron_jobs.name'Run the schedulerCron jobs defined insettings.CRONMAN_JOBS_MODULEare started bycron_schedulercommand fromcronapp.
This command constructs a list of jobs that should be executed in current period (now +/- 1 minute)
and createsa new subprocessfor each job.python manage.py cron_scheduler runThis command should be added to system's crontab on server responsible for running periodic tasks
and executed every 2 minutes.Run single cron jobCommandcron_worker run <job spec>is responsible for executing cron jobs:python manage.py cron_worker run HelloWorldCron job parametersCron job classes can accept parameters which are passed torunmethod as positional or named arguments:classHelloWorld(BaseCronJob):"""Demo Cron Job class"""defrun(self,what,sleep=None):"""Main logic"""print"Hello{}".format(what)ifsleep:time.sleep(int(sleep))...python manage.py cron_worker run HelloWorld:world,sleep=5Parameters are passed as string values, any type casts should be made inrunmethod.
Quoted string with spaces are supported, but comma can be used only as argument separator:python manage.py cron_worker run HelloWorld:"big world",sleep=5There are utility functions for extracting lists and boolean values incronman.utilsmodule.Configure Cronitor supportcron_workercommand can notify Cronitor when a job is started, finished or it has failed.
To enable this you have to:Enable Cronitor support in settingsCRONMAN_CRONITOR_ENABLED = TrueConfigure you cron job class:classHelloWorld(BaseCronJob):"""Demo Cron Job class"""cronitor_id='ab12z'# ID is assigned in Cronitor's dashboardWe may disable sending optional "RUN" and "FAIL" pings to Cronitor when cron job starts by settingcronitor_ping_run = Falseorcronitor_ping_fail = Falsebut this doesn't seem to be necessary.Important note:When adding a new monitor in Cronitor dashboard, please use typeheartbeat. Avoid usingcron jobmonitors, as they're sending false-positive alerts "Has not run on schedule".Configure lockTasks can acquire locks to prevent concurrent calls. Locks have form of PIDfiles located insettings.CRONMAN_DATA_DIR. To modify lock behavior for given cron job class you can setlock_typeattribute:fromcronman.taxonomiesimportLockTypeclassHelloWorld(BaseCronJob):"""Demo Cron Job class"""lock_type=LockType.PARAMSThe following values are supported:None- no lock, concurrency is allowedLockType.CLASS(default) - only one instance of given cron job class can be run at the same time (e.g.Foo:p=1andFoo:p=2can't work concurrently)LockType.PARAMS- only one combination of class and params can be run at the same time (e.g.Foo:p=1andFoo:p=2can work concurrently, but another call toFoo:p=1will be prohibited)
Locks acquired/released bycron_workercommand.We can configure a shared lock for several cron job classes to make sure only one of them is running:fromcronman.taxonomiesimportLockTypeclassHelloWorld1(BaseCronJob):"""Demo Cron Job class (1)"""lock_type=LockType.CLASSlock_name='HelloWorld'classHelloWorld2(BaseCronJob):"""Demo Cron Job class (2)"""lock_type=LockType.CLASSlock_name='HelloWorld'Configure CPU and IO priorityWe can assign CPU priority (nice) to a cron job class by usingworker_cpu_priorityattribute:fromcronman.taxonomiesimportCPUPriorityclassNiceHellowWorld(BaseCronJob):"""Hello World running through `nice -n 19`"""worker_cpu_priority=CPUPriority.LOWESTWe can also customize IO priority (ionice) by assigning one of values fromcronman.taxonomies.IOPrioritytoworker_io_priorityattribute, but this is not necessary in most cases, asnicechanges IO priority as well.Commandscron_scheduler run,cron_worker resume, and cron jobRunCronTaskswill spawn worker processes with respect to CPU and IO priorities assigned to cron job classes. These settingsare notenforced when runningcron_worker runso you have to prependnice/ioniceto such calls manually.List and kill running cron jobsCommandcron_worker statusshows currently running cron jobs - PIDfile name, PID and status (ALIVE,DEAD).
Search results can be limited byjob spec(cron job name, parameters):python manage.py cron_worker status
python manage.py cron_worker status Foo
python manage.py cron_worker status Foo:bar=1Commandcron_worker killkills active cron jobs, gracefully (SIGTERM) or by force when process refuses to die (SIGKILL). List of tasks can be limited byjob spec:python manage.py cron_worker kill
python manage.py cron_worker kill Foo
python manage.py cron_worker kill Foo:bar=1Single process can be killed also using PID:python manage.py cron_worker kill 39078Resuming cron jobsSubset of cron jobs can be resumed after being killed:classResumableHelloWorld(BaseCronJob):"""Demo Cron Job class"""can_resume=TrueCommandcron_worker resumestarts all killed cron jobs withcan_resumecapability:python manage.py cron_worker resumeTo remove all entries about dead cron jobs and make sure they won't be resumed we can runcron_worker cleancommand:python manage.py cron_worker cleanCommandcron_worker suspendcleans all previous entries about dead cron jobs and then kills all running ones to make sure that nextresumewill raise only recently killed jobs:python manage.py cron_worker suspendList available cron jobsCommandcron_worker infoshows list of all available cron jobs:python manage.py cron_worker infoWhen cron job name is passed to this command, system displays docstring and parameters of given cron job:python manage.py cron_worker info FooDisable the schedulerScheduler command can be disabled temporarily:python manage.py cron_scheduler disableand re-enabled later:python manage.py cron_scheduler enableCalls tocron_scheduler runwill not spawn worker processes while scheduler is disabled.Send errors to sentryErrors in cron job classes are intercepted bycron_workerand sent to Sentry using the same config as other Django commands (settings.RAVEN_MANAGEMENT_COMMAND_CONFIG).
Ifsettings.CRONMAN_RAVEN_CMDis defined, the scheduler will use it as execution script for worker processes, e.g.python manage.py cron_worker run Foo:bar=1will be converted to{CRONMAN_RAVEN_CMD} -c "python manage.py cron_worker run Foo:bar=1"Cron Tasks - running cron jobs from Admin areaSome cron jobs can be requested to start from Admin area:Admin > Cron > Cron TasksTo add a cron job class to the list in Admin we need to setALLOWED_CRON_TASKSsetting:ALLOWED_CRON_TASKS=('HelloWorld',)To request another run of given cron job we can just create a newCronTaskrecord in Admin.
Cron jobRunCronTasksstarted every 4 minutes by the scheduler will spawn a separate worker process for each pending Cron Task.Changelog2021-01-20 - 3.0.0 Remove Python 2 checks. Fix issue with suspend all.
2020-05-25 - 2.1.0 Python 3 + Django 2 compatibility.
2020-04-30 - 2.0.1 Fix for sentry-sdk.
2020-04-23 - 2.0.0 Replace raven with sentry-sdk.
2020-01-09 - 1.2.0 Django 2 compatibility.
2019-04-30 - 1.1.1 Pre-commit.com hooks support. Docs update
2019-03-13 - 1.1.0 Add support for cronitor ping for cron_scheduler
2019-02-25 - 1.0.0 Initial version released