.. _guide-beat:

================
 Periodic Tasks
================

.. contents::
    :local:

Introduction
============

:program:`celerybeat` is a scheduler.  It kicks off tasks at regular intervals,
which are then executed by the worker nodes available in the cluster.

By default the entries are taken from the :setting:`CELERYBEAT_SCHEDULE` setting,
but custom stores can also be used, like storing the entries
in an SQL database.

You have to ensure only a single scheduler is running for a schedule
at a time, otherwise you would end up with duplicate tasks.  Using
a centralized approach means the schedule does not have to be synchronized,
and the service can operate without using locks.

.. _beat-entries:

Entries
=======

To schedule a task periodically you have to add an entry to the
:setting:`CELERYBEAT_SCHEDULE` setting.

Example: Run the ``tasks.add`` task every 30 seconds.

.. code-block:: python

    from datetime import timedelta

    CELERYBEAT_SCHEDULE = {
        "runs-every-30-seconds": {
            "task": "tasks.add",
            "schedule": timedelta(seconds=30),
            "args": (16, 16)
        },
    }


Using a :class:`~datetime.timedelta` for the schedule means the task will
be executed 30 seconds after ``celerybeat`` starts, and then every 30 seconds
after the last run.  A crontab like schedule also exists, see the section
on `Crontab schedules`_.

.. _beat-entry-fields:

Available Fields
----------------

* ``task``

    The name of the task to execute.

* ``schedule``

    The frequency of execution.

    This can be the number of seconds as an integer, a
    :class:`~datetime.timedelta`, or a :class:`~celery.schedules.crontab`.
    You can also define your own custom schedule types, by extending the
    interface of :class:`~celery.schedules.schedule`.

* ``args``

    Positional arguments (:class:`list` or :class:`tuple`).

* ``kwargs``

    Keyword arguments (:class:`dict`).

* ``options``

    Execution options (:class:`dict`).

    This can be any argument supported by :meth:`~celery.execute.apply_async`,
    e.g. ``exchange``, ``routing_key``, ``expires``, and so on.

* ``relative``

    By default :class:`~datetime.timedelta` schedules are scheduled
    "by the clock". This means the frequency is rounded to the nearest
    second, minute, hour or day depending on the period of the timedelta.

    If ``relative`` is true the frequency is not rounded and will be
    relative to the time when :program:`celerybeat` was started.

.. _beat-crontab:

Crontab schedules
=================

If you want more control over when the task is executed, for
example, a particular time of day or day of the week, you can use
the ``crontab`` schedule type:

.. code-block:: python

    from celery.schedules import crontab

    CELERYBEAT_SCHEDULE = {
        # Executes every monday morning at 7:30 A.M
        "every-monday-morning": {
            "task": "tasks.add",
            "schedule": crontab(hour=7, minute=30, day_of_week=1),
            "args": (16, 16),
        },
    }

The syntax of these crontab expressions are very flexible.  Some examples:

+-------------------------------------+--------------------------------------------+
| **Example**                         | **Meaning**                                |
+-------------------------------------+--------------------------------------------+
| crontab()                           | Execute every minute.                      |
+-------------------------------------+--------------------------------------------+
| crontab(minute=0, hour=0)           | Execute daily at midnight.                 |
+-------------------------------------+--------------------------------------------+
| crontab(minute=0,                   | Execute every three hours---at midnight,   |
|                                     | 3am, 6am, 9am, noon, 3pm, 6pm, 9pm.        |
+-------------------------------------+--------------------------------------------+
| crontab(minute=0,                   | Same as previous.                          |
|         hour=[0,3,6,9,12,15,18,21]) |                                            |
+-------------------------------------+--------------------------------------------+
| crontab(minute="\*/15")             | Execute every 15 minutes.                  |
+-------------------------------------+--------------------------------------------+
| crontab(day_of_week="sunday")       | Execute every minute (!) at sundays.       |
+-------------------------------------+--------------------------------------------+
| crontab(minute="*",                 | Same as previous.                          |
|         hour="*",                   |                                            |
|         day_of_week="sun")          |                                            |
+-------------------------------------+--------------------------------------------+
| crontab(minute="\*/10",             | Execute every ten minutes, but only        |
|         hour="3,17,22",             | between 3-4 am, 5-6 pm and 10-11 pm on     |
|         day_of_week="thu,fri")      | thursdays or fridays.                      |
+-------------------------------------+--------------------------------------------+
| crontab(minute=0, hour="\*/2,\*/3") | Execute every even hour, and every hour    |
|                                     | divisable by three. This means:            |
|                                     | at every hour *except*: 1am,               |
|                                     | 5am, 7am, 11am, 1pm, 5pm, 7pm,             |
|                                     | 11pm                                       |
+-------------------------------------+--------------------------------------------+
| crontab(minute=0, hour="\*/5")      | Execute hour divisable by 5. This means    |
|                                     | that it is triggered at 3pm, not 5pm       |
|                                     | (since 3pm equals the 24-hour clock        |
|                                     | value of "15", which is divisable by 5).   |
+-------------------------------------+--------------------------------------------+
| crontab(minute=0, hour="\*/3,8-17") | Execute every hour divisable by 3, and     |
|                                     | every hour during office hours (8am-5pm).  |
+-------------------------------------+--------------------------------------------+

.. _beat-starting:

Starting celerybeat
===================

To start the :program:`celerybeat` service::

    $ celerybeat

You can also start ``celerybeat`` with ``celeryd`` by using the ``-B`` option,
this is convenient if you only intend to use one worker node::

    $ celeryd -B

Celerybeat needs to store the last run times of the tasks in a local database
file (named ``celerybeat-schedule`` by default), so it needs access to
write in the current directory, or alternatively you can specify a custom
location for this file::

    $ celerybeat -s /home/celery/var/run/celerybeat-schedule


.. note::

    To daemonize celerybeat see :ref:`daemonizing`.

.. _beat-custom-schedulers:

Using custom scheduler classes
------------------------------

Custom scheduler classes can be specified on the command line (the ``-S``
argument).  The default scheduler is :class:`celery.beat.PersistentScheduler`,
which is simply keeping track of the last run times in a local database file
(a :mod:`shelve`).

``django-celery`` also ships with a scheduler that stores the schedule in the
Django database::

    $ celerybeat -S djcelery.schedulers.DatabaseScheduler

Using ``django-celery``'s scheduler you can add, modify and remove periodic
tasks from the Django Admin.
