Skip to contentSkip to conversation

Asynchronous email notifications, task execution

PATCH In review Diana Thayer 2 participants 2 messages Aug 25, 2017 – Sep 1, 2017

lore
Share & tools
lore
#0 lore raw

PATCH v4 1/1 Asynchronous email notifications, task execution

This patch adds asynchronous task execution using a Celery backend and RabbitMQ task queue, so that the layer submission process to proceed even in the event that sending the notification email fails, and establishing an asynchronous execution mechanism that we can use in the future e.g. for triggering parse operations from the web UI. This pertains to bug 11195:

https://bugzilla.yoctoproject.org/show_bug.cgi?id=11195

It updates the README to reflect the installation and configuration of a basic RabbitMQ setup, adds a 'tasks.py' file to contain task definitions, updates the 'edit_layer_view' function to send emails to administrators about new and updated layers asynchronously, and modifies the 'settings.py' to include a default configuration for a RabbitMQ connection.

---
 README              | 10 +++++++++-
 TODO                |  1 -
 layerindex/tasks.py | 24 ++++++++++++++++++++++++
 layerindex/views.py |  5 ++---
 requirements.txt    |  1 +
 settings.py         |  4 ++++
 6 files changed, 40 insertions(+), 5 deletions(-)
 create mode 100644 layerindex/tasks.py
README +9 -1
index 62f739d..c7f7409 100644
@@ -14,6 +14,7 @@ In order to make use of this application you will need:
 * Python 3.4+
 * Django 1.8.x - tested with 1.8.17; newer versions may work, but
   the application has not been tested with 1.9 or newer.
+* RabbitMQ 3.6.x - tested with 3.6.10.
 * For production usage, a web server set up to host Django applications
   (not needed for local-only testing)
 * A database supported by Django (SQLite, MySQL, etc.). Django takes
@@ -41,7 +42,9 @@ Setup instructions:
 1. Edit settings.py to specify a database, EMAIL_HOST, SECRET_KEY and
    other settings specific to your installation. Ensure you set
    LAYER_FETCH_DIR to an absolute path to a location with sufficient
-   space for fetching layer repositories.
+   space for fetching layer repositories. Modify RABBIT_BROKER
+   and RABBIT_BACKEND to reflect the settings used by your RabbitMQ
+   server.
 
 2. Run the following commands within the layerindex-web directory to
    initialise the database:
@@ -64,6 +67,11 @@ Setup instructions:
    production you need to use a proper web server and have DEBUG set
    to False.
 
+   3.1. In order to process asynchronous tasks like sending email,
+        you will need to run a Celery worker:
+
+        celery -A layerindex.tasks worker --loglevel=info
+
 4. You'll need to add at least the openembedded-core layer to the
    database, or some equivalent that contains conf/bitbake.conf for
    the base system configuration. To add this, follow these steps:
TODO +0 -1
index 186219f..29986ac 100644
@@ -27,7 +27,6 @@ Other
 * Show layer type in layer detail?
 * Usage links in list page?
 * Subdirs in list page?
-* Prevent SMTP failures from breaking submission process
 * Query backend service i.e. special URL to query information for external apps/scripts
 * Add comparison to duplicates page
 * Create simple script to check for unlisted layer subdirectories in all repos
layerindex/tasks.py new file +24 -0
new file mode 100644
index 0000000..de80804
@@ -0,0 +1,24 @@
+from celery import Celery
+from django.core.mail import EmailMessage
+from . import utils
+import os
+import time
+
+try:
+    import settings
+except ImportError:
+    # not in a full django env, so settings is inaccessible.
+    # setup django to access settings.
+    utils.setup_django()
+    import settings
+
+tasks = Celery('layerindex',
+    broker=settings.RABBIT_BROKER,
+    backend=settings.RABBIT_BACKEND)
+
[email protected]
+def send_email(subject, text_content, from_email=settings.DEFAULT_FROM_EMAIL, to_emails=[]):
+    # We seem to need to run this within the task
+    utils.setup_django()
+    msg = EmailMessage(subject, text_content, from_email, to_emails)
+    msg.send()
layerindex/views.py +2 -3
index 1661cb3..bcf6671 100644
@@ -19,7 +19,6 @@ from layerindex.forms import EditLayerForm, LayerMaintainerFormSet, EditNoteForm
 from django.db import transaction
 from django.contrib.auth.models import User, Permission
 from django.db.models import Q, Count, Sum
-from django.core.mail import EmailMessage
 from django.template.loader import get_template
 from django.template import Context
 from django.utils.decorators import method_decorator
@@ -28,6 +27,7 @@ from django.contrib import messages
 from reversion.models import Revision
 from . import utils
 from . import simplesearch
+from . import tasks
 import settings
 from django.dispatch import receiver
 import reversion
@@ -181,8 +181,7 @@ def edit_layer_view(request, template_name, branch='master', slug=None):
                         from_email = settings.SUBMIT_EMAIL_FROM
                         to_email = user.email
                         text_content = plaintext.render(d)
-                        msg = EmailMessage(subject, text_content, from_email, [to_email])
-                        msg.send()
+                        tasks.send_email.apply_async((subject, text_content, from_email, [to_email]))
                     return HttpResponseRedirect(reverse('submit_layer_thanks'))
             messages.success(request, 'Layer %s saved successfully.' % layeritem.name)
             if return_url:
requirements.txt +1 -0
index f80e5d4..7cd741b 100644
@@ -1,3 +1,4 @@
+celery==3.1.25
 Django==1.8.17
 django-cors-headers==1.1.0
 django-nvd3==0.9.7
settings.py +4 -0
index 92146f8..e26f4b2 100644
@@ -224,3 +224,7 @@ FORCE_REVIEW_HTTPS = False
 # Settings for layer submission feature
 SUBMIT_EMAIL_FROM = '[email protected]'
 SUBMIT_EMAIL_SUBJECT = 'OE Layerindex layer submission'
+
+# RabbitMQ settings
+RABBIT_BROKER = 'amqp://'
+RABBIT_BACKEND = 'rpc://'
Signature · 1 line
2.7.4
#1 lore raw

Hi Diana,

Quoted 9 lines · NZST Diana Thayer

This patch adds asynchronous task execution using a Celery backend and RabbitMQ task queue, so that the layer submission process to proceed even in the event that sending the notification email fails, and establishing an asynchronous execution mechanism that we can use in the future e.g. for triggering parse operations from the web UI. This pertains to bug 11195:

https://bugzilla.yoctoproject.org/show_bug.cgi?id=11195

Quoted 8 lines

It updates the README to reflect the installation and configuration of a basic RabbitMQ setup, adds a 'tasks.py' file to contain task definitions, updates the 'edit_layer_view' function to send emails to administrators about new and updated layers asynchronously, and modifies the 'settings.py' to include a default configuration for a RabbitMQ connection.

Thanks! I've just merged this, with your changes to the dockerfile in the other patch squashed in. I did tweak the commit message just a little, fixing the bug reference and adding mention of the dockerfile change.

I'll get in touch with Michael Halstead about updating the OE index instance.

Cheers,
Paul

Signature · 2 lines
Paul Eggleton
Intel Open Source Technology Centre