mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-01 07:35:34 -05:00
Merge pull request #2862 from alphagov/ses-client-stub
Stub SES email client to avoid hitting SES during load testing
This commit is contained in:
@@ -21,6 +21,7 @@ from app.celery.celery import NotifyCelery
|
|||||||
from app.clients import Clients
|
from app.clients import Clients
|
||||||
from app.clients.document_download import DocumentDownloadClient
|
from app.clients.document_download import DocumentDownloadClient
|
||||||
from app.clients.email.aws_ses import AwsSesClient
|
from app.clients.email.aws_ses import AwsSesClient
|
||||||
|
from app.clients.email.aws_ses_stub import AwsSesStubClient
|
||||||
from app.clients.sms.firetext import FiretextClient
|
from app.clients.sms.firetext import FiretextClient
|
||||||
from app.clients.sms.mmg import MMGClient
|
from app.clients.sms.mmg import MMGClient
|
||||||
from app.clients.performance_platform.performance_platform_client import PerformancePlatformClient
|
from app.clients.performance_platform.performance_platform_client import PerformancePlatformClient
|
||||||
@@ -49,6 +50,7 @@ notify_celery = NotifyCelery()
|
|||||||
firetext_client = FiretextClient()
|
firetext_client = FiretextClient()
|
||||||
mmg_client = MMGClient()
|
mmg_client = MMGClient()
|
||||||
aws_ses_client = AwsSesClient()
|
aws_ses_client = AwsSesClient()
|
||||||
|
aws_ses_stub_client = AwsSesStubClient()
|
||||||
encryption = Encryption()
|
encryption = Encryption()
|
||||||
zendesk_client = ZendeskClient()
|
zendesk_client = ZendeskClient()
|
||||||
statsd_client = StatsdClient()
|
statsd_client = StatsdClient()
|
||||||
@@ -81,13 +83,22 @@ def create_app(application):
|
|||||||
logging.init_app(application, statsd_client)
|
logging.init_app(application, statsd_client)
|
||||||
firetext_client.init_app(application, statsd_client=statsd_client)
|
firetext_client.init_app(application, statsd_client=statsd_client)
|
||||||
mmg_client.init_app(application, statsd_client=statsd_client)
|
mmg_client.init_app(application, statsd_client=statsd_client)
|
||||||
|
|
||||||
aws_ses_client.init_app(application.config['AWS_REGION'], statsd_client=statsd_client)
|
aws_ses_client.init_app(application.config['AWS_REGION'], statsd_client=statsd_client)
|
||||||
|
aws_ses_stub_client.init_app(
|
||||||
|
application.config['AWS_REGION'],
|
||||||
|
statsd_client=statsd_client,
|
||||||
|
stub_url=application.config['SES_STUB_URL']
|
||||||
|
)
|
||||||
|
# If a stub url is provided for SES, then use the stub client rather than the real SES boto client
|
||||||
|
email_clients = [aws_ses_stub_client] if application.config['SES_STUB_URL'] else [aws_ses_client]
|
||||||
|
clients.init_app(sms_clients=[firetext_client, mmg_client], email_clients=email_clients)
|
||||||
|
|
||||||
notify_celery.init_app(application)
|
notify_celery.init_app(application)
|
||||||
encryption.init_app(application)
|
encryption.init_app(application)
|
||||||
redis_store.init_app(application)
|
redis_store.init_app(application)
|
||||||
performance_platform_client.init_app(application)
|
performance_platform_client.init_app(application)
|
||||||
document_download_client.init_app(application)
|
document_download_client.init_app(application)
|
||||||
clients.init_app(sms_clients=[firetext_client, mmg_client], email_clients=[aws_ses_client])
|
|
||||||
metrics.init_app(application)
|
metrics.init_app(application)
|
||||||
|
|
||||||
register_blueprint(application)
|
register_blueprint(application)
|
||||||
|
|||||||
@@ -43,10 +43,14 @@ def process_ses_results(self, response):
|
|||||||
except NoResultFound:
|
except NoResultFound:
|
||||||
message_time = iso8601.parse_date(ses_message['mail']['timestamp']).replace(tzinfo=None)
|
message_time = iso8601.parse_date(ses_message['mail']['timestamp']).replace(tzinfo=None)
|
||||||
if datetime.utcnow() - message_time < timedelta(minutes=5):
|
if datetime.utcnow() - message_time < timedelta(minutes=5):
|
||||||
|
current_app.logger.info(
|
||||||
|
f"notification not found for reference: {reference} (update to {notification_status}). "
|
||||||
|
f"Callback may have arrived before notification was persisted to the DB. Adding task to retry queue"
|
||||||
|
)
|
||||||
self.retry(queue=QueueNames.RETRY)
|
self.retry(queue=QueueNames.RETRY)
|
||||||
else:
|
else:
|
||||||
current_app.logger.warning(
|
current_app.logger.warning(
|
||||||
"notification not found for reference: {} (update to {})".format(reference, notification_status)
|
f"notification not found for reference: {reference} (update to {notification_status})"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
49
app/clients/email/aws_ses_stub.py
Normal file
49
app/clients/email/aws_ses_stub.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from flask import current_app
|
||||||
|
from requests import request
|
||||||
|
from time import monotonic
|
||||||
|
|
||||||
|
from app.clients.email import (EmailClientException, EmailClient)
|
||||||
|
|
||||||
|
|
||||||
|
class AwsSesStubClientException(EmailClientException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AwsSesStubClient(EmailClient):
|
||||||
|
def init_app(self, region, statsd_client, stub_url):
|
||||||
|
self.name = 'ses'
|
||||||
|
self.statsd_client = statsd_client
|
||||||
|
self.url = stub_url
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def send_email(self,
|
||||||
|
source,
|
||||||
|
to_addresses,
|
||||||
|
subject,
|
||||||
|
body,
|
||||||
|
html_body='',
|
||||||
|
reply_to_address=None):
|
||||||
|
try:
|
||||||
|
start_time = monotonic()
|
||||||
|
response = request(
|
||||||
|
"POST",
|
||||||
|
self.url,
|
||||||
|
data={"id": "dummy-data"},
|
||||||
|
timeout=60
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
response_json = json.loads(response.text)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.statsd_client.incr("clients.ses_stub.error")
|
||||||
|
raise AwsSesStubClientException(str(e))
|
||||||
|
else:
|
||||||
|
elapsed_time = monotonic() - start_time
|
||||||
|
current_app.logger.info("AWS SES stub request finished in {}".format(elapsed_time))
|
||||||
|
self.statsd_client.timing("clients.ses_stub.request-time", elapsed_time)
|
||||||
|
self.statsd_client.incr("clients.ses_stub.success")
|
||||||
|
return response_json['MessageId']
|
||||||
@@ -345,6 +345,7 @@ class Config(object):
|
|||||||
# these environment vars aren't defined in the manifest so to set them on paas use `cf set-env`
|
# these environment vars aren't defined in the manifest so to set them on paas use `cf set-env`
|
||||||
MMG_URL = os.environ.get("MMG_URL", "https://api.mmg.co.uk/jsonv2a/api.php")
|
MMG_URL = os.environ.get("MMG_URL", "https://api.mmg.co.uk/jsonv2a/api.php")
|
||||||
FIRETEXT_URL = os.environ.get("FIRETEXT_URL", "https://www.firetext.co.uk/api/sendsms/json")
|
FIRETEXT_URL = os.environ.get("FIRETEXT_URL", "https://www.firetext.co.uk/api/sendsms/json")
|
||||||
|
SES_STUB_URL = os.environ.get("SES_STUB_URL")
|
||||||
|
|
||||||
AWS_REGION = 'eu-west-1'
|
AWS_REGION = 'eu-west-1'
|
||||||
|
|
||||||
@@ -485,6 +486,7 @@ class Live(Config):
|
|||||||
PERFORMANCE_PLATFORM_ENABLED = True
|
PERFORMANCE_PLATFORM_ENABLED = True
|
||||||
API_RATE_LIMIT_ENABLED = True
|
API_RATE_LIMIT_ENABLED = True
|
||||||
CHECK_PROXY_HEADER = True
|
CHECK_PROXY_HEADER = True
|
||||||
|
SES_STUB_URL = None
|
||||||
|
|
||||||
CRONITOR_ENABLED = True
|
CRONITOR_ENABLED = True
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user