diff --git a/doc/admin/config.rst b/doc/admin/config.rst index 753b78af0f..e0c4d6d721 100644 --- a/doc/admin/config.rst +++ b/doc/admin/config.rst @@ -210,4 +210,21 @@ to speed up various operations:: If no redis is configured, pretix will store sessions and locks in the database. If memcached is configured, memcached will be used for caching instead of redis. -.. _Python documentation: https://docs.python.org/3/library/configparser.html?highlight=configparser#supported-ini-file-structure \ No newline at end of file +Celery task queue +----------------- + +For processing long-running tasks asynchronously, pretix needs help of the celery task queue. +For communicating between the web server and the task workers in both direction, a messaging +queue and a result backend is needed. You can use a redis database for both directions, or +an AMQP server (e.h. RabbitMQ) as a broker and redis or your database as a result backend:: + + [celery] + broker=amqp://guest:guest@localhost:5672// + backend=redis://localhost/0 + +RabbitMQ might be the better choice if you have a complex, multi-server, high-performance setup, +but as you already should have a redis instance ready for session and lock storage, we recommend +redis for convenience. See the `Celery documentation`_ for more details. + +.. _Python documentation: https://docs.python.org/3/library/configparser.html?highlight=configparser#supported-ini-file-structure +.. _Celery documentation: http://docs.celeryproject.org/en/latest/configuration.html \ No newline at end of file diff --git a/src/pretix/__init__.py b/src/pretix/__init__.py index 6c8e6b979c..7f6d5e1c44 100644 --- a/src/pretix/__init__.py +++ b/src/pretix/__init__.py @@ -1 +1,6 @@ __version__ = "0.0.0" + +try: + from .celery import app as celery_app +except ImportError: + pass diff --git a/src/pretix/base/services/mail.py b/src/pretix/base/services/mail.py index 7b8457cdf9..09db5e9e05 100644 --- a/src/pretix/base/services/mail.py +++ b/src/pretix/base/services/mail.py @@ -2,7 +2,6 @@ import logging from django.conf import settings from django.core.mail import EmailMessage -from django.core.urlresolvers import reverse from django.template.loader import get_template from django.utils import translation from django.utils.translation import ugettext as _ @@ -66,10 +65,16 @@ def mail(user: User, subject: str, template: str, context: dict=None, event: Eve } ) body += "\r\n" + try: + return mail_send([user.email], subject, body, sender) + finally: + translation.activate(_lng) + +def mail_send(to, subject, body, sender): email = EmailMessage( subject, body, sender, - to=[user.email] + to=to ) try: @@ -78,5 +83,10 @@ def mail(user: User, subject: str, template: str, context: dict=None, event: Eve except Exception: logger.exception('Error sending e-mail') return False - finally: - translation.activate(_lng) + + +if settings.HAS_CELERY: + from pretix.celery import app + + mail_send_task = app.task(mail_send) + mail_send = lambda *args, **kwargs: mail_send_task.apply_async(args=args, kwargs=kwargs) diff --git a/src/pretix/celery.py b/src/pretix/celery.py new file mode 100644 index 0000000000..0fcaeaf456 --- /dev/null +++ b/src/pretix/celery.py @@ -0,0 +1,12 @@ +import os + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pretix.settings") + +from django.conf import settings + +if settings.HAS_CELERY: + from celery import Celery + app = Celery('pretix') + + app.config_from_object('django.conf:settings') + app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) diff --git a/src/pretix/settings.py b/src/pretix/settings.py index 3aa2b5fadf..153682b054 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -114,6 +114,12 @@ if HAS_REDIS: SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "redis" +HAS_CELERY = config.has_option('celery', 'broker') +if HAS_CELERY: + BROKER_URL = config.get('celery', 'broker') + CELERY_RESULT_BACKEND = config.get('celery', 'backend') + CELERY_SEND_TASK_ERROR_EMAILS = bool(ADMINS) + # Internal settings STATIC_ROOT = '_static' @@ -330,3 +336,6 @@ LOGGING = { } }, } + +CELERY_TASK_SERIALIZER = 'json' +CELERY_RESULT_SERIALIZER = 'json' diff --git a/src/requirements/celery.txt b/src/requirements/celery.txt new file mode 100644 index 0000000000..dc922d80b8 --- /dev/null +++ b/src/requirements/celery.txt @@ -0,0 +1,2 @@ +celery>=3.1,<3.2 + diff --git a/src/setup.cfg b/src/setup.cfg index 8dea531cde..7587d8ffb5 100644 --- a/src/setup.cfg +++ b/src/setup.cfg @@ -12,4 +12,4 @@ known_first_party = pretix known_third_party = versions multi_line_output = 5 not_skip = __init__.py -skip = make_testdata.py,wsgi.py,bootstrap +skip = make_testdata.py,wsgi.py,bootstrap,celery.py