| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 | .. _internals-guide:================================ Contributors Guide to the Code================================.. contents::    :local:Philosophy==========The API>RCP Precedence Rule---------------------------- The API is more important than Readability- Readability is more important than Convention- Convention is more important than Performance    - …unless the code is a proven hot-spot.More important than anything else is the end-user API.Conventions must step aside, and any suffering is always alleviatedif the end result is a better API.Conventions and Idioms Used===========================Classes-------Naming~~~~~~- Follows :pep:`8`.- Class names must be `CamelCase`.- but not if they're verbs, verbs shall be `lower_case`:    .. code-block:: python        # - test case for a class        class TestMyClass(Case):                # BAD            pass        class test_MyClass(Case):               # GOOD            pass        # - test case for a function        class TestMyFunction(Case):             # BAD            pass        class test_my_function(Case):           # GOOD            pass        # - "action" class (verb)        class UpdateTwitterStatus(object):    # BAD            pass        class update_twitter_status(object):    # GOOD            pass    .. note::        Sometimes it makes sense to have a class mask as a function,        and there's precedence for this in the Python standard library (e.g.,        :class:`~contextlib.contextmanager`). Celery examples include        :class:`~celery.signature`, :class:`~celery.chord`,        ``inspect``, :class:`~kombu.utils.functional.promise` and more..- Factory functions and methods must be `CamelCase` (excluding verbs):    .. code-block:: python        class Celery(object):            def consumer_factory(self):     # BAD                ...            def Consumer(self):             # GOOD                ...Default values~~~~~~~~~~~~~~Class attributes serve as default values for the instance,as this means that they can be set by either instantiation or inheritance.**Example:**.. code-block:: python    class Producer(object):        active = True        serializer = 'json'        def __init__(self, serializer=None, active=None):            self.serializer = serializer or self.serializer            # must check for None when value can be false-y            self.active = active if active is not None else self.activeA subclass can change the default value:.. code-block:: python    TaskProducer(Producer):        serializer = 'pickle'and the value can be set at instantiation:.. code-block:: pycon    >>> producer = TaskProducer(serializer='msgpack')Exceptions~~~~~~~~~~Custom exceptions raised by an objects methods and propertiesshould be available as an attribute and documented in themethod/property that throw.This way a user doesn't have to find out where to import theexception from, but rather use ``help(obj)`` and accessthe exception class from the instance directly.**Example**:.. code-block:: python    class Empty(Exception):        pass    class Queue(object):        Empty = Empty        def get(self):            """Get the next item from the queue.            :raises Queue.Empty: if there are no more items left.            """            try:                return self.queue.popleft()            except IndexError:                raise self.Empty()Composites~~~~~~~~~~Similarly to exceptions, composite classes should be override-able byinheritance and/or instantiation. Common sense can be used whenselecting what classes to include, but often it's better to add onetoo many: predicting what users need to override is hard (this hassaved us from many a monkey patch).**Example**:.. code-block:: python    class Worker(object):        Consumer = Consumer        def __init__(self, connection, consumer_cls=None):            self.Consumer = consumer_cls or self.Consumer        def do_work(self):            with self.Consumer(self.connection) as consumer:                self.connection.drain_events()Applications vs. "single mode"==============================In the beginning Celery was developed for Django, simply becausethis enabled us get the project started quickly, while also havinga large potential user base.In Django there's a global settings object, so multiple Django projectscan't co-exist in the same process space, this later posed a problemfor using Celery with frameworks that don't have this limitation.Therefore the app concept was introduced. When using apps you use 'celery'objects instead of importing things from Celery sub-modules, this(unfortunately) also means that Celery essentially has two API's.Here's an example using Celery in single-mode:.. code-block:: python    from celery import task    from celery.task.control import inspect    from .models import CeleryStats    @task    def write_stats_to_db():        stats = inspect().stats(timeout=1)        for node_name, reply in stats:            CeleryStats.objects.update_stat(node_name, stats)and here's the same using Celery app objects:.. code-block:: python    from .celery import celery    from .models import CeleryStats    @app.task    def write_stats_to_db():        stats = celery.control.inspect().stats(timeout=1)        for node_name, reply in stats:            CeleryStats.objects.update_stat(node_name, stats)In the example above the actual application instance is importedfrom a module in the project, this module could look something like this:.. code-block:: python    from celery import Celery    app = Celery(broker='amqp://')Module Overview===============- celery.app    This is the core of Celery: the entry-point for all functionality.- celery.loaders    Every app must have a loader. The loader decides how configuration    is read; what happens when the worker starts; when a task starts and ends;    and so on.    The loaders included are:        - app            Custom Celery app instances uses this loader by default.        - default            "single-mode" uses this loader by default.    Extension loaders also exist, for example :pypi:`celery-pylons`.- celery.worker    This is the worker implementation.- celery.backends    Task result backends live here.- celery.apps    Major user applications: worker and beat.    The command-line wrappers for these are in celery.bin (see below)- celery.bin    Command-line applications.    :file:`setup.py` creates setuptools entry-points for these.- celery.concurrency    Execution pool implementations (prefork, eventlet, gevent, solo).- celery.db    Database models for the SQLAlchemy database result backend.    (should be moved into :mod:`celery.backends.database`)- celery.events    Sending and consuming monitoring events, also includes curses monitor,    event dumper and utilities to work with in-memory cluster state.- celery.execute.trace    How tasks are executed and traced by the worker, and in eager mode.- celery.security    Security related functionality, currently a serializer using    cryptographic digests.- celery.task    single-mode interface to creating tasks, and controlling workers.- t.unit (int distribution)    The unit test suite.- celery.utils    Utility functions used by the Celery code base.    Much of it is there to be compatible across Python versions.- celery.contrib    Additional public code that doesn't fit into any other name-space.Worker overview===============* `celery.bin.worker:Worker`   This is the command-line interface to the worker.   Responsibilities:       * Daemonization when :option:`--detach <celery worker --detach>` set,       * dropping privileges when using :option:`--uid <celery worker --uid>`/         :option:`--gid <celery worker --gid>` arguments       * Installs "concurrency patches" (eventlet/gevent monkey patches).  ``app.worker_main(argv)`` calls  ``instantiate('celery.bin.worker:Worker')(app).execute_from_commandline(argv)``* `app.Worker` -> `celery.apps.worker:Worker`   Responsibilities:   * sets up logging and redirects standard outs   * installs signal handlers (`TERM`/`HUP`/`STOP`/`USR1` (cry)/`USR2` (rdb))   * prints banner and warnings (e.g., pickle warning)   * handles the :option:`celery worker --purge` argument* `app.WorkController` -> `celery.worker.WorkController`   This is the real worker, built up around bootsteps.
 |