From d32d3f5a093e727e8519a85bf8ae266ff580bbd2 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Thu, 13 Oct 2022 01:38:24 +0200 Subject: [PATCH] Docs updates (#6) * Update django docs links to 4.0 * Update Django Q to Django Q2 * Use different theme to make difference more clear between the original and this forked one * Added info notice about this fork * Some small layout/typo fixes --- .readthedocs.yaml | 4 ++++ README.rst | 33 ++++++++++++++++++-------------- docs/Dockerfile | 7 +++++++ docs/_static/logo.png | Bin 6134 -> 0 bytes docs/_static/logo_large.png | Bin 28750 -> 0 bytes docs/architecture.rst | 2 +- docs/brokers.rst | 20 +++++++++---------- docs/cluster.rst | 4 ++-- docs/conf.py | 37 +++++++++++++++++------------------- docs/configure.rst | 32 +++++++++++++++---------------- docs/docker-compose.yaml | 7 +++++++ docs/errors.rst | 4 ++-- docs/examples.rst | 8 ++++---- docs/index.rst | 13 +++++++------ docs/install.rst | 33 +++++++++++++------------------- docs/requirements.txt | 1 + docs/signals.rst | 4 ++-- docs/tasks.rst | 9 +++------ 18 files changed, 115 insertions(+), 103 deletions(-) create mode 100644 docs/Dockerfile delete mode 100644 docs/_static/logo.png delete mode 100644 docs/_static/logo_large.png create mode 100644 docs/docker-compose.yaml create mode 100644 docs/requirements.txt diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 61086de..799deb1 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -14,3 +14,7 @@ build: # Build documentation in the docs/ directory with Sphinx sphinx: configuration: docs/conf.py + +python: + install: + - requirements: docs/requirements.txt diff --git a/README.rst b/README.rst index 4cdbf57..686d415 100644 --- a/README.rst +++ b/README.rst @@ -3,6 +3,10 @@ A multiprocessing distributed task queue for Django |image0| |image1| |docs| +:: + + Django Q2 is a fork of Django Q. Big thanks to Ilan Steemers for starting this project. Unfortunately, development has stalled since June 2021. Django Q2 is the new updated version of Django Q, with dependencies updates, docs updates and several bug fixes. Original repository: https://github.com/Koed00/django-q + Features ~~~~~~~~ @@ -30,12 +34,12 @@ Tested with: Python 3.7, 3.8, 3.9, 3.10 Django 2.2.X and 3.2.X Brokers ~~~~~~~ -- `Redis `__ -- `Disque `__ -- `IronMQ `__ -- `Amazon SQS `__ -- `MongoDB `__ -- `Django ORM `__ +- `Redis `__ +- `Disque `__ +- `IronMQ `__ +- `Amazon SQS `__ +- `MongoDB `__ +- `Django ORM `__ Installation ~~~~~~~~~~~~ @@ -56,9 +60,9 @@ Installation $ python manage.py migrate -- Choose a message `broker `__ , configure and install the appropriate client library. +- Choose a message `broker `__ , configure and install the appropriate client library. -Read the full documentation at `https://django-q.readthedocs.org `__ +Read the full documentation at `https://django-q2.readthedocs.org `__ Configuration @@ -82,10 +86,11 @@ All configuration settings are optional. e.g: 'redis': { 'host': '127.0.0.1', 'port': 6379, - 'db': 0, } + 'db': 0, + } } -For full configuration options, see the `configuration documentation `__. +For full configuration options, see the `configuration documentation `__. Management Commands ~~~~~~~~~~~~~~~~~~~ @@ -138,7 +143,7 @@ Use `async_task` from your code to quickly offload tasks: def print_result(task): print(task.result) -For more info see `Tasks `__ +For more info see `Tasks `__ Schedule @@ -183,7 +188,7 @@ Admin page or directly from your code: schedule_type=Schedule.CRON, cron = '0 22 * * 1-5') -For more info check the `Schedules `__ documentation. +For more info check the `Schedules `__ documentation. Testing @@ -248,8 +253,8 @@ Acknowledgements - JetBrains for their `Open Source Support Program `__ -.. |image0| image:: https://github.com/GDay/django-q/workflows/Tests/badge.svg?branche=master - :target: https://github.com/Koed00/django-q/actions?query=workflow%3Atests +.. |image0| image:: https://github.com/GDay/django-q2/actions/workflows/test.yml/badge.svg?branche=master + :target: https://github.com/GDay/django-q2/actions?query=workflow%3Atests .. |image1| image:: https://coveralls.io/repos/github/GDay/django-q2/badge.svg?branch=master :target: https://coveralls.io/github/GDay/django-q2?branch=master .. |docs| image:: https://readthedocs.org/projects/docs/badge/?version=latest diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 0000000..526940f --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,7 @@ +FROM sphinxdoc/sphinx + +RUN mkdir -p /docs +WORKDIR /docs +COPY . . +RUN pip3 install -r requirements.txt +RUN make html diff --git a/docs/_static/logo.png b/docs/_static/logo.png deleted file mode 100644 index 3e2613acfbd728eac46391ab4a645a58f23f36e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6134 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 diff --git a/docs/_static/logo_large.png b/docs/_static/logo_large.png deleted file mode 100644 index 84b0cc00be08ce7b6cce96a1e67187e429bc2ac0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28750 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 diff --git a/docs/architecture.rst b/docs/architecture.rst index 062480a..50a1cf3 100644 --- a/docs/architecture.rst +++ b/docs/architecture.rst @@ -2,7 +2,7 @@ Architecture ------------ .. image:: _static/cluster.png - :alt: Django Q schema + :alt: Django Q2 schema Signed Tasks diff --git a/docs/brokers.rst b/docs/brokers.rst index ebb737a..0cf6f19 100644 --- a/docs/brokers.rst +++ b/docs/brokers.rst @@ -1,7 +1,7 @@ Brokers ======= -The broker sits between your Django instances and your Django Q cluster instances; accepting, saving and delivering task packages. +The broker sits between your Django instances and your Django Q2 cluster instances; accepting, saving and delivering task packages. Currently we support a variety of brokers from the default Redis, bleeding edge Disque to the convenient ORM and fast MongoDB. The default Redis broker does not support message receipts. @@ -11,7 +11,7 @@ Keep in mind this is not the same as a failing task. If a tasks code crashes, th Even though this might be acceptable in some use cases, you might prefer brokers with message receipts support. These guarantee delivery by waiting for the cluster to send a receipt after the task has been processed. In case a receipt has not been received after a set time, the task package is put back in the queue. -Django Q supports this behavior by setting the :ref:`retry` timer on brokers that support message receipts. +Django Q2 supports this behavior by setting the :ref:`retry` timer on brokers that support message receipts. Some pointers: @@ -29,7 +29,7 @@ Support for more brokers is being worked on. Redis ----- -The default broker for Django Q clusters. +The default broker for Django Q2 clusters. * Atomic * Requires `Redis-py `__ client library: ``pip install redis`` @@ -47,7 +47,7 @@ Bulk task retrieval is supported via the :ref:`bulk` option. * Delivery receipts * Atomic -* Needs Django's `Cache framework `__ configured for monitoring +* Needs Django's `Cache framework `__ configured for monitoring * Compatible with `Tynd `__ Disque addon on `Heroku `__ * Still considered Alpha software * Supports bulk dequeue @@ -60,7 +60,7 @@ This HTTP based queue service is both available directly via `Iron.io `__ configured for monitoring +* Needs Django's `Cache framework `__ configured for monitoring * Requires the `iron-mq `__ client library: ``pip install iron-mq`` * See the :ref:`ironmq_configuration` configuration section for options. @@ -72,7 +72,7 @@ Although `SQS `__ is not the fastest, it is stable, * Delivery receipts * Maximum message size is 256Kb * Supports bulk dequeue up to 10 messages with a maximum total size of 256Kb -* Needs Django's `Cache framework `__ configured for monitoring +* Needs Django's `Cache framework `__ configured for monitoring * Requires the `boto3 `__ client library: ``pip install boto3`` * See the :ref:`sqs_configuration` configuration section for options. @@ -83,7 +83,7 @@ This highly scalable NoSQL database makes for a very fast and reliably persisten Usually available on most PaaS providers, as `open-source `__ or commercial `enterprise `__ edition. * Delivery receipts -* Needs Django's `Cache framework `__ configured for monitoring +* Needs Django's `Cache framework `__ configured for monitoring * Can be configured as the Django cache-backend through several open-source cache providers. * Requires the `pymongo `__ driver: ``pip install pymongo`` * See the :ref:`mongo_configuration` configuration section for options. @@ -98,8 +98,8 @@ However for a medium message rate and scheduled tasks, this is the most convenie * Delivery receipts * Supports bulk dequeue -* Needs Django's `Cache framework `__ configured for monitoring -* Can be `configured `__ as its own cache backend. +* Needs Django's `Cache framework `__ configured for monitoring +* Can be `configured `__ as its own cache backend. * Queue editable in Django Admin * See the :ref:`orm_configuration` configuration on how to set it up. @@ -118,7 +118,7 @@ You can override the :class:`Broker` or any of its existing derived broker types def info(self): return 'My Custom Broker' -Using the :ref:`broker_class` configuration setting you can then instruct Django Q to use this instead of one of the existing brokers: +Using the :ref:`broker_class` configuration setting you can then instruct Django Q2 to use this instead of one of the existing brokers: .. code-block:: python diff --git a/docs/cluster.rst b/docs/cluster.rst index 886259e..dc73bb9 100644 --- a/docs/cluster.rst +++ b/docs/cluster.rst @@ -3,7 +3,7 @@ Cluster ======= .. py:currentmodule:: django_q -Django Q uses Python's multiprocessing module to manage a pool of workers that will handle your tasks. +Django Q2 uses Python's multiprocessing module to manage a pool of workers that will handle your tasks. Start your cluster using Django's ``manage.py`` command:: $ python manage.py qcluster @@ -60,7 +60,7 @@ If you host on `Heroku `__ or you are using `Honcho `__ or `Circus `__ it is not strictly necessary. +While you certainly can run a Django Q2 with a process manager like `Supervisor `__ or `Circus `__ it is not strictly necessary. The cluster has an internal sentinel that checks the health of all the processes and recycles or reincarnates according to your settings or in case of unexpected crashes. Because of the multiprocessing daemonic nature of the cluster, it is impossible for a process manager to determine the clusters health and resource usage. diff --git a/docs/conf.py b/docs/conf.py index 9f63e07..433769c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,7 +16,7 @@ import os import sys -import alabaster +import sphinx_rtd_theme myPath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, myPath + '/../') @@ -37,7 +37,7 @@ nitpick_ignore = [('py:class', 'datetime')] # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'alabaster', + 'sphinx_rtd_theme', 'sphinx.ext.todo', 'sphinx.ext.intersphinx', # 'sphinx.ext.autodoc' @@ -62,9 +62,9 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = 'Django Q' -copyright = '2015-2021, Ilan Steemers' -author = 'Ilan Steemers' +project = 'Django Q2' +copyright = '2015-2021, Ilan Steemers - 2022, Stan Triepels' +author = 'Ilan Steemers, Stan Triepels' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -124,19 +124,16 @@ todo_include_todos = True # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation.None html_theme_options = { - 'description': "A multiprocessing task queue for Django", - 'logo': 'logo.png', - 'github_user': 'Koed00', - 'github_repo': 'django-q', - 'github_banner': True, - 'travis_button': True, - 'analytics_id': 'UA-64807059-1' + # 'description': "A multiprocessing task queue for Django", + # 'github_user': 'GDay', + # 'github_repo': 'django-q2', + # 'github_banner': True, } html_sidebars = { '**': [ @@ -147,7 +144,7 @@ html_sidebars = { ] } # Add any paths that contain custom themes here, relative to this directory. -html_theme_path = [alabaster.get_path()] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to @@ -232,7 +229,7 @@ html_static_path = ['_static'] # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'DjangoQdoc' +htmlhelp_basename = 'DjangoQ2doc' # -- Options for LaTeX output --------------------------------------------- @@ -254,13 +251,13 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'DjangoQ.tex', 'Django Q Documentation', + (master_doc, 'DjangoQ2.tex', 'Django Q2 Documentation', 'Ilan Steemers', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -latex_logo = '_static/logo_large.png' +# latex_logo = '_static/logo_large.png' # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. @@ -284,7 +281,7 @@ latex_logo = '_static/logo_large.png' # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'djangoq', 'Django Q Documentation', + (master_doc, 'djangoq2', 'Django Q2 Documentation', [author], 1) ] @@ -299,8 +296,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'DjangoQ', 'Django Q Documentation', - author, 'DjangoQ', 'A multiprocessing distributed task queue for Django.', + (master_doc, 'DjangoQ2', 'Django Q2 Documentation', + author, 'DjangoQ2', 'A multiprocessing distributed task queue for Django.', 'Miscellaneous'), ] diff --git a/docs/configure.rst b/docs/configure.rst index 45b78f2..69fb955 100644 --- a/docs/configure.rst +++ b/docs/configure.rst @@ -16,7 +16,7 @@ Configuration is handled via the ``Q_CLUSTER`` dictionary in your :file:`setting 'save_limit': 250, 'queue_limit': 500, 'cpu_affinity': 1, - 'label': 'Django Q', + 'label': 'Django Q2', 'redis': { 'host': '127.0.0.1', 'port': 6379, @@ -96,7 +96,7 @@ Only works with brokers that support delivery receipts. Defaults to 60. The value must be bigger than the time it takes to complete longest task, i.e. :ref:`timeout` must be less than retry value and all tasks must complete in less time than the selected retry time. If this does not hold, i.e. the retry value is less than timeout or less than it takes to finish a task, -Django-Q will start the task again if the used broker supports receipts. +Django-Q2 will start the task again if the used broker supports receipts. For example, with the following code @@ -167,7 +167,7 @@ Defaults to ``workers**2``. label ~~~~~ -The label used for the Django Admin page. Defaults to ``'Django Q'`` +The label used for the Django Admin page. Defaults to ``'Django Q2'`` .. _catch_up: @@ -225,7 +225,7 @@ of the cache connection you want to use instead of a direct Redis connection:: .. tip:: - Django Q uses your ``SECRET_KEY`` to sign task packages and prevent task crossover. So make sure you have it set up in your Django settings. + Django Q2 uses your ``SECRET_KEY`` to sign task packages and prevent task crossover. So make sure you have it set up in your Django settings. .. _disque_configuration: @@ -243,7 +243,7 @@ If you want to use Disque as your broker, set this to a list of available Disque } -Django Q is also compatible with the `Tynd Disque `__ addon on `Heroku `__:: +Django Q2 is also compatible with the `Tynd Disque `__ addon on `Heroku `__:: # example Tynd Disque connection import os @@ -339,15 +339,15 @@ Using the Django ORM backend will also enable the Queued Tasks table in the Admi If you need better performance , you should consider using a different database backend than the main project. Set ``orm`` to the name of that database connection and make sure you run migrations on it using the ``--database`` option. -When using the Django database as a message broker, you can set the ``has_replica`` boolean keyword to ensure Django-Q works properly letting a `Database Router `__. :: +When using the Django database as a message broker, you can set the ``has_replica`` boolean keyword to ensure Django-Q2 works properly letting a `Database Router `__. :: # example ORM broker connection with replica database Q_CLUSTER = { - ... - 'orm': 'default', - 'has_replica': True - } + ... + 'orm': 'default', + 'has_replica': True + } .. _mongo_configuration: @@ -364,8 +364,8 @@ To use MongoDB as a message broker you simply provide the connection information 'retry': 70, 'queue_limit': 100, 'mongo': { - 'host': '127.0.0.1', - 'port': 27017 + 'host': '127.0.0.1', + 'port': 27017 } } @@ -389,7 +389,7 @@ You can use a custom broker class for your cluster workers:: 'name': 'Custom', 'workers': 8, 'timeout': 60, - 'broker_class: 'myapp.broker.CustomBroker' + 'broker_class': 'myapp.broker.CustomBroker' } Make sure your ``CustomBroker`` class inherits from either the base :class:`Broker` class or one of its children. @@ -431,7 +431,7 @@ Defaults to ``True`` error_reporter ~~~~~~~~~~~~~~ -You can redirect worker exceptions directly to various error reporters (for example `Rollbar `__ or `Sentry `__) by installing Django Q with the necessary `extras `__. +You can redirect worker exceptions directly to various error reporters (for example `Rollbar `__ or `Sentry `__) by installing Django Q2 with the necessary `extras `__. To enable installed error reporters, you must provide the configuration settings required by an error reporter extension:: @@ -440,12 +440,12 @@ To enable installed error reporters, you must provide the configuration settings 'error_reporter': { 'rollbar': { 'access_token': '32we33a92a5224jiww8982', - 'environment': 'Django-Q' + 'environment': 'Django-Q2' } } } -For more information on error reporters and developing error reporting plugins for Django Q, see :doc:`errors`. +For more information on error reporters and developing error reporting plugins for Django Q2, see :doc:`errors`. cpu_affinity ~~~~~~~~~~~~ diff --git a/docs/docker-compose.yaml b/docs/docker-compose.yaml new file mode 100644 index 0000000..5536a59 --- /dev/null +++ b/docs/docker-compose.yaml @@ -0,0 +1,7 @@ +version: "3.0" +services: + docs: + container_name: djangoq2-docs + build: . + volumes: + - .:/docs diff --git a/docs/errors.rst b/docs/errors.rst index dd95eec..41acb10 100644 --- a/docs/errors.rst +++ b/docs/errors.rst @@ -2,8 +2,8 @@ Errors ------ .. py:currentmodule:: django_q -Django Q uses a pluggable error reporter system based upon python `extras `__, allowing anyone to develop plugins for their favorite error reporting and monitoring integration. Currently implemented examples include `Rollbar `__ and `Sentry `__. +Django Q2 uses a pluggable error reporter system based upon python `extras `__, allowing anyone to develop plugins for their favorite error reporting and monitoring integration. Currently implemented examples include `Rollbar `__ and `Sentry `__. -Error reporting plugins register a class which implements a ``report`` method, which is invoked when a Django Q cluster encounters an error, passing information to the particular service. Error reporters must be :ref:`configured` via the ``Q_CLUSTER`` dictionary in your :file:`settings.py`. These settings are passed as kwargs upon initiation of the Error Reporter. Therefore, in order to implement a new plugin, a package must expose a class which will be instantiated with the necessary information via the ``Q_CLUSTER`` settings and implements a single ``report`` method. +Error reporting plugins register a class which implements a ``report`` method, which is invoked when a Django Q2 cluster encounters an error, passing information to the particular service. Error reporters must be :ref:`configured` via the ``Q_CLUSTER`` dictionary in your :file:`settings.py`. These settings are passed as kwargs upon initiation of the Error Reporter. Therefore, in order to implement a new plugin, a package must expose a class which will be instantiated with the necessary information via the ``Q_CLUSTER`` settings and implements a single ``report`` method. For example implementations, see `django-q-rollbar `__ and `django-q-sentry `__ diff --git a/docs/examples.rst b/docs/examples.rst index 455d4b8..daf52c4 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -38,7 +38,7 @@ Sending an email can take a while so why not queue it: # this schedule will erase itself after having run -Since you're only telling Django Q to take care of the emails, you can quickly move on to serving web pages to your user. +Since you're only telling Django Q2 to take care of the emails, you can quickly move on to serving web pages to your user. Signals ======= @@ -142,7 +142,7 @@ The hook is practical here, because it allows us to detach the sending task from Haystack ======== If you use `Haystack `__ as your projects search engine, -here's an example of how you can have Django Q take care of your indexes in real time using model signals: +here's an example of how you can have Django Q2 take care of your indexes in real time using model signals: .. code-block:: python @@ -286,7 +286,7 @@ Adapted from `Sebastian Raschka's blog `__. + If you have an example you want to share, please submit a pull request on `github `__. diff --git a/docs/index.rst b/docs/index.rst index 865d728..feed7ed 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,9 +3,12 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to Django Q -=================== -Django Q is a native Django task queue, scheduler and worker application using Python multiprocessing. +Welcome to Django Q2 +==================== +Django Q2 is a native Django task queue, scheduler and worker application using Python multiprocessing. + +.. note:: + Django Q2 is a fork of Django Q. Big thanks to Ilan Steemers for starting this project. Unfortunately, development of Django Q has stalled since June 2021. Django Q2 is the new updated version of Django Q, with dependencies updates, docs updates and several bug fixes. Original repository: https://github.com/Koed00/django-q Features @@ -24,7 +27,7 @@ Features - Rollbar and Sentry support -Django Q is tested with: Python 3.7 and 3.8, Django 2.2.x and 3.2.x +Django Q is tested with: Python 3.7, 3.8, 3.9 and 3.10, Django 2.2.x and 3.2.x Currently available in English, German and French. @@ -50,5 +53,3 @@ Contents: Examples * :ref:`genindex` -* :ref:`search` - diff --git a/docs/install.rst b/docs/install.rst index b1e274a..a546bd0 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -18,20 +18,20 @@ Installation $ python manage.py migrate -- Choose a message :doc:`broker` , configure it and install the appropriate client library. +- Choose a message :doc:`broker`, configure it and install the appropriate client library. -- Run Django Q cluster in order to handle tasks async:: +- Run Django Q2 cluster in order to handle tasks async:: $ python manage.py qcluster Requirements ------------ -Django Q is tested for Python 3.7, 3.8 and 3.9 +Django Q2 is tested for Python 3.7, 3.8, 3.9 and 3.10 - `Django `__ - Django Q aims to use as much of Django's standard offerings as possible + Django Q2 aims to use as much of Django's standard offerings as possible The code is tested against Django versions `2.2.x` and `3.2.x`. Please note that Django versions below 2.0 do not support Python 3.7 @@ -76,7 +76,7 @@ Optional $ pip install pymongo -- `Redis `__ server is the default broker for Django Q. It provides the best performance and does not require Django's cache framework for monitoring. +- `Redis `__ server is the default broker for Django Q2. It provides the best performance and does not require Django's cache framework for monitoring. - `Disque `__ server is based on Redis by the same author, but focuses on reliable queues. Currently in Alpha, but highly recommended. You can either build it from source or use it on Heroku through the `Tynd `__ beta. @@ -110,16 +110,13 @@ Add-ons - `django-q-email `__ is a compatible Django email backend that will automatically async queue your emails. -Compatibility -------------- -Django Q is still a young project. If you do find any incompatibilities please submit an issue on `github `__. OS X ~~~~ -Running Django Q on OS X should work fine, except for the following known issues: +Running Django Q2 on OS X should work fine, except for the following known issues: * :meth:`multiprocessing.Queue.qsize()` is not supported. This leads to the monitor not reporting the internal queue size of clusters running under OS X. -* CPU count through :func:`multiprocessing.cpu_count()` does not work. Installing :ref:`psutil` provides Django Q with an alternative way of determining the number of CPU's on your system +* CPU count through :func:`multiprocessing.cpu_count()` does not work. Installing :ref:`psutil` provides Django Q2 with an alternative way of determining the number of CPU's on your system * CPU affinity is provided by :ref:`psutil` which at this time does not support this feature on OSX. The code however is aware of this and will fake the CPU affinity assignment in the logs without actually assigning it. This way you can still develop with this setting. Windows @@ -130,14 +127,13 @@ This will run all ``async`` calls inline through a single cluster worker without Other known issues are: * :func:`os.getppid()` is only supported under windows since Python 3.2. If you use an older version you need to install :ref:`psutil` as an alternative. -* CPU count through :func:`multiprocessing.cpu_count()` occasionally fails on servers. Installing :ref:`psutil` provides Django Q with an alternative way of determining the number of CPU's on your system +* CPU count through :func:`multiprocessing.cpu_count()` occasionally fails on servers. Installing :ref:`psutil` provides Django Q2 with an alternative way of determining the number of CPU's on your system * The monitor and info commands rely on the Curses package which is not officially supported on windows. There are however some ports available like `this one `__ by Christoph Gohlke. Python ~~~~~~ -The code is always tested against the latest version Python 3 and we try to stay compatible with the last two versions of each. -Current tests are performed with 3.7 and 3.8 -If you do encounter any regressions with earlier versions, please submit an issue on `github `__ +Current tests are performed with 3.7, 3.8, 3.9 and 3.10 +If you do encounter any regressions with earlier versions, please submit an issue on `github `__ .. note:: @@ -146,16 +142,13 @@ If you do encounter any regressions with earlier versions, please submit an issu Open-source packages ~~~~~~~~~~~~~~~~~~~~ -Django Q is always tested with the latest versions of the required and optional Python packages. We try to keep the dependencies as up to date as possible. -You can reference the `requirements `__ file to determine which versions are currently being used for tests and development. +Django Q2 is always tested with the latest versions of the required and optional Python packages. We try to keep the dependencies as up to date as possible. +You can reference the `requirements `__ file to determine which versions are currently being used for tests and development. Django ~~~~~~ We strive to be compatible with last two major version of Django. -At the moment this means we support the 2.2.x and 3.1.x releases. +At the moment this means we support the 2.2.x and 3.2.x releases. Since we are now no longer supporting Python 2, we can also not support older versions of Django that do not support Python >= 3.6 For this you can always use older releases, but they are no longer maintained. - - - diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..5babfe3 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +sphinx-rtd-theme==1.0.0 diff --git a/docs/signals.rst b/docs/signals.rst index 7d27041..e30ae85 100644 --- a/docs/signals.rst +++ b/docs/signals.rst @@ -5,7 +5,7 @@ Signals Available signals ----------------- -Django Q emits the following signals during its lifecycle. +Django Q2 emits the following signals during its lifecycle. Before enqueuing a task """"""""""""""""""""""" @@ -33,7 +33,7 @@ executed by a worker and processed by the monitor. It included the ``task`` dict Subscribing to a signal ----------------------- -Connecting to a Django Q signal is done the same as any other Django +Connecting to a Django Q2 signal is done the same as any other Django signal:: from django.dispatch import receiver diff --git a/docs/tasks.rst b/docs/tasks.rst index d631cdc..0c5f2cb 100644 --- a/docs/tasks.rst +++ b/docs/tasks.rst @@ -7,9 +7,6 @@ Tasks async_task() ------------ -.. warning:: Since Python 3.7 `async` became a reserved keyword and was refactored to `async_task` - - Use :func:`async_task` from your code to quickly offload tasks to the :class:`Cluster`: .. code:: python @@ -101,7 +98,7 @@ Please note that this will override any other option keywords. .. note:: For tasks to be processed you will need to have a worker cluster running in the background using ``python manage.py qcluster`` - or you need to configure Django Q to run in synchronous mode for testing using the :ref:`sync` option. + or you need to configure Django Q2 to run in synchronous mode for testing using the :ref:`sync` option. AsyncTask @@ -221,7 +218,7 @@ Instead of setting ``sync`` on each individual ``async_task`` you can also confi Connection pooling ------------------ -Django Q tries to pass broker instances around its parts as much as possible to save you from running out of connections. +Django Q2 tries to pass broker instances around its parts as much as possible to save you from running out of connections. When you are making individual calls to :func:`async_task` a lot though, it can help to set up a broker to reuse for :func:`async_task`: .. code:: python @@ -236,7 +233,7 @@ When you are making individual calls to :func:`async_task` a lot though, it can .. tip:: - If you are using `django-redis `__ and the redis broker, you can :ref:`configure ` Django Q to use its connection pool. + If you are using `django-redis `__ and the redis broker, you can :ref:`configure ` Django Q2 to use its connection pool. Reference