-
Notifications
You must be signed in to change notification settings - Fork 420
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Send activation emails from a worker process
Send new user account activation emails from a worker process, instead of from the main application thread. This avoids a problem when the register view is called and sending the email (mailer.send(message)) raises an exception *but the email was actually sent*. The transaction would be rolled back and the user account not created, and the user would receive an unusable "please activate your account" email. Changes: - The register view callable now puts a message on a new "activations" nsq topic, instead of actually sending the email. - The new h/accounts/worker.py is a hypothesis-worker that subscribes to the new "activations" topic and actually sends an email for each message published to the toipic. - Update accounts/test/views_test.py to fix broken tests. These were mainly broken because _register() now accesses request.get_queue_writer() and Pyramid's DummyRequest() objects don't have that method. Just use a mock.Mock() instead. In a couple of places assertions had to be updated as well. In sending the email fails (if pyramid_mailer's send_immediately() raises) then the message will be requeued (this is gnsq's default behavior when a worker function raises an exception) and the worker will try again to send it. Note that we don't attempt to prevent sending the same activation email multiple times if a message published to the "activations" topic is received by the worker multiple times. This may happen, since nsq guarantees "at least once" delivery. If this becomes a problem we may need to set a flag in the database to record when a particular activation email has already been sent successfully.
- Loading branch information
Showing
5 changed files
with
45 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
web: gunicorn -w ${WEB_CONCURRENCY:-1} --paster conf/${HYP_ENV:-production}.ini | ||
notification: hypothesis-worker conf/${HYP_ENV:-production}.ini notification | ||
nipsa: hypothesis-worker conf/${HYP_ENV:-production}.ini nipsa | ||
activation: hypothesis-worker conf/${HYP_ENV:-production}.ini activation | ||
assets: hypothesis assets conf/${HYP_ENV:-production}.ini | ||
initdb: hypothesis initdb conf/${HYP_ENV:-production}.ini |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# -*- coding: utf-8 -*- | ||
import json | ||
|
||
import pyramid_mailer | ||
|
||
|
||
def worker(request): | ||
"""Subscribe to the "activations" topic and send activation emails.""" | ||
def handle_message(reader, message): | ||
body = json.loads(message.body) | ||
email = pyramid_mailer.message.Message( | ||
subject=body['subject'], recipients=body['recipients'], | ||
body=body['body']) | ||
pyramid_mailer.get_mailer(request).send_immediately(email) | ||
|
||
reader = request.get_queue_reader('activations', 'mailer') | ||
reader.on_message.connect(handle_message) | ||
reader.start(block=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters