Made SMS messages go through celery

- twilio client pulled in from delivery app
- made method to perform task
This commit is contained in:
Martyn Inglis
2016-02-15 16:01:14 +00:00
parent ffbe94f390
commit 223cb8c2dd
9 changed files with 145 additions and 31 deletions

View File

@@ -12,12 +12,14 @@ from config import configs
from utils import logging
from notify_client import NotifyAPIClient
from app.celery.celery import NotifyCelery
from app.clients.sms.twilio import TwilioClient
db = SQLAlchemy()
ma = Marshmallow()
notify_alpha_client = NotifyAPIClient()
celery = NotifyCelery()
twilio_client = TwilioClient()
api_user = LocalProxy(lambda: _request_ctx_stack.top.api_user)
@@ -32,7 +34,7 @@ def create_app(config_name, config_overrides=None):
ma.init_app(application)
init_app(application, config_overrides)
logging.init_app(application)
twilio_client.init_app(application)
celery.init_app(application)
from app.service.rest import service as service_blueprint

View File

@@ -1,9 +1,33 @@
from app import celery
from app.dao.services_dao import get_model_services
from itsdangerous import URLSafeSerializer
from app import celery, twilio_client, db
from app.clients.sms.twilio import TwilioClientException
from app.dao.templates_dao import get_model_templates
from app.models import Notification
from flask import current_app
@celery.task(name="refresh-services")
def refresh_services():
print(get_model_services())
for service in get_model_services():
celery.control.add_consumer(str(service.id))
@celery.task(name="send-sms", bind="True")
def send_sms(service_id, notification_id, encrypted_notification, secret_key, salt):
serializer = URLSafeSerializer(secret_key)
notification = serializer.loads(encrypted_notification, salt=salt)
template = get_model_templates(notification['template'])
status = 'sent'
try:
twilio_client.send_sms(notification, template.content)
except TwilioClientException as e:
current_app.logger.info(e)
status = 'failed'
notification_db_object = Notification(
id=notification_id,
template_id=notification['template'],
to=notification['to'],
service_id=service_id,
status=status
)
db.session.add(notification_db_object)
db.session.commit()

13
app/clients/__init__.py Normal file
View File

@@ -0,0 +1,13 @@
class ClientException(Exception):
'''
Base Exceptions for sending notifications that fail
'''
pass
class Client(object):
'''
Base client for sending notifications.
'''
pass

View File

@@ -0,0 +1,17 @@
from app.clients import (Client, ClientException)
class SmsClientException(ClientException):
'''
Base Exception for SmsClients
'''
pass
class SmsClient(Client):
'''
Base Sms client for sending smss.
'''
def send_sms(self, *args, **kwargs):
raise NotImplemented('TODO Need to implement.')

48
app/clients/sms/twilio.py Normal file
View File

@@ -0,0 +1,48 @@
import logging
from app.clients.sms import (
SmsClient, SmsClientException)
from twilio.rest import TwilioRestClient
from twilio import TwilioRestException
logger = logging.getLogger(__name__)
class TwilioClientException(SmsClientException):
pass
class TwilioClient(SmsClient):
'''
Twilio sms client.
'''
def init_app(self, config, *args, **kwargs):
super(TwilioClient, self).__init__(*args, **kwargs)
self.client = TwilioRestClient(
config.config.get('TWILIO_ACCOUNT_SID'),
config.config.get('TWILIO_AUTH_TOKEN'))
self.from_number = config.config.get('TWILIO_NUMBER')
print(config.config)
def send_sms(self, notification, content):
try:
response = self.client.messages.create(
body=content,
to=notification['to'],
from_=self.from_number
)
return response.sid
except TwilioRestException as e:
logger.exception(e)
raise TwilioClientException(e)
def status(self, message_id):
try:
response = self.client.messages.get(message_id)
if response.status in ('delivered', 'undelivered', 'failed'):
return response.status
return None
except TwilioRestException as e:
logger.exception(e)
raise TwilioClientException(e)

View File

@@ -3,43 +3,50 @@ import uuid
from flask import (
Blueprint,
jsonify,
request
)
request,
current_app)
from itsdangerous import URLSafeSerializer
from app import api_user
from app.aws_sqs import add_notification_to_queue
from app.dao import (templates_dao)
from app.schemas import (
email_notification_schema, sms_template_notification_schema)
from app import celery
from app.celery.tasks import send_sms
notifications = Blueprint('notifications', __name__)
def create_notification_id():
return str(uuid.uuid4())
@notifications.route('/<notification_id>', methods=['GET'])
def get_notifications(notification_id):
# TODO return notification id details
return jsonify({'id': notification_id}), 200
@celery.task(name="make-sms", bind="True")
def send_sms(self):
print('Executing task id {0.id}, args: {0.args!r} kwargs: {0.kwargs!r}'.format(self.request))
from time import sleep
sleep(0.5)
print('finished')
@notifications.route('/sms', methods=['POST'])
def create_sms_notification():
serializer = URLSafeSerializer(current_app.config.get('SECRET_KEY'))
resp_json = request.get_json()
notification, errors = sms_template_notification_schema.load(resp_json)
if errors:
return jsonify(result="error", message=errors), 400
send_sms.delay()
notification_id = add_notification_to_queue(api_user['client'], notification['template'], 'sms', notification)
notification_id = create_notification_id()
encrypted_notification = serializer.dumps(notification, current_app.config.get('DANGEROUS_SALT'))
send_sms.apply_async((
api_user['client'],
notification_id,
encrypted_notification,
current_app.config.get('SECRET_KEY'),
current_app.config.get('DANGEROUS_SALT')))
return jsonify({'notification_id': notification_id}), 201

View File

@@ -22,7 +22,7 @@ class Config(object):
# Notification Queue names are a combination of a prefx plus a name
NOTIFICATION_QUEUE_PREFIX = 'notification'
BROKER_URL = 'amqp://guest:guest@localhost:5672//'
BROKER_URL = 'sqs://'
BROKER_TRANSPORT_OPTIONS = {
'region': 'eu-west-1',
'polling_interval': 10, # 1 second
@@ -33,13 +33,16 @@ class Config(object):
CELERY_TIMEZONE = 'Europe/London'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERYBEAT_SCHEDULE = {
'refresh-queues': {
'task': 'refresh-services',
'schedule': timedelta(seconds=5)
}
}
# CELERYBEAT_SCHEDULE = {
# 'refresh-queues': {
# 'task': 'refresh-services',
# 'schedule': timedelta(seconds=5)
# }
# }
CELERY_IMPORTS = ('app.celery.tasks',)
TWILIO_ACCOUNT_SID = os.getenv('TWILIO_ACCOUNT_SID')
TWILIO_AUTH_TOKEN = os.getenv('TWILIO_AUTH_TOKEN')
TWILIO_NUMBER = os.getenv('TWILIO_NUMBER')
class Development(Config):

View File

@@ -14,7 +14,8 @@ Flask-Bcrypt==0.6.2
credstash==1.8.0
boto3==1.2.3
celery==3.1.20
redis==2.10.5
twilio==4.6.0
git+https://github.com/alphagov/notifications-python-client.git@0.2.6#egg=notifications-python-client==0.2.6

View File

@@ -1,7 +1,6 @@
#!/usr/bin/env python
import os
from app import celery, create_app
from app.celery.tasks import refresh_services
application = create_app(os.getenv('NOTIFY_API_ENVIRONMENT') or 'development')
application.app_context().push()