mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-03 09:51:11 -05:00
Merge pull request #129 from GSA/queue-investigation
SMS provider cleanup
This commit is contained in:
2
Pipfile
2
Pipfile
@@ -49,7 +49,6 @@ lxml = "==4.9.1"
|
||||
marshmallow = "==3.15.0"
|
||||
marshmallow-sqlalchemy = "==0.28.1"
|
||||
notifications-python-client = "==6.3.0"
|
||||
notifications-utils = {editable = true, ref = "11b9d3dbde8d73910c05b0cb8e74d9f93b45a7b0", git = "https://github.com/GSA/notifications-utils"}
|
||||
oscrypto = "==1.3.0"
|
||||
psycopg2-binary = "==2.9.3"
|
||||
pyjwt = "==2.4.0"
|
||||
@@ -59,6 +58,7 @@ werkzeug = "~=2.1.1"
|
||||
# gds metrics packages
|
||||
prometheus-client = "==0.14.1"
|
||||
gds-metrics = {version = "==0.2.4", ref = "6f1840a57b6fb1ee40b7e84f2f18ec229de8aa72", git = "https://github.com/alphagov/gds_metrics_python.git"}
|
||||
notifications-utils = {editable = true, ref = "37ae9753c050851453d072994fb03b1415601716", git = "https://github.com/GSA/notifications-utils"}
|
||||
|
||||
[dev-packages]
|
||||
flake8 = "==4.0.1"
|
||||
|
||||
124
Pipfile.lock
generated
124
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "adeddc01285ee3e46e1a1464cceffc5fd1d151c61f069642e1c716b8e9fd0507"
|
||||
"sha256": "d652255c8ca6f6cb96778b0159228628816a114f867510bd4ce13a9e9692b101"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -476,11 +476,11 @@
|
||||
},
|
||||
"importlib-metadata": {
|
||||
"hashes": [
|
||||
"sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab",
|
||||
"sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"
|
||||
"sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b",
|
||||
"sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313"
|
||||
],
|
||||
"markers": "python_version < '3.10'",
|
||||
"version": "==5.0.0"
|
||||
"version": "==5.1.0"
|
||||
},
|
||||
"iso8601": {
|
||||
"hashes": [
|
||||
@@ -710,7 +710,7 @@
|
||||
"notifications-utils": {
|
||||
"editable": true,
|
||||
"git": "https://github.com/GSA/notifications-utils",
|
||||
"ref": "11b9d3dbde8d73910c05b0cb8e74d9f93b45a7b0"
|
||||
"ref": "37ae9753c050851453d072994fb03b1415601716"
|
||||
},
|
||||
"orderedset": {
|
||||
"hashes": [
|
||||
@@ -736,10 +736,10 @@
|
||||
},
|
||||
"phonenumbers": {
|
||||
"hashes": [
|
||||
"sha256:93745d7afd38e246660bb601b07deac54eeb76c8e5e43f5e83333b0383a0a1e4",
|
||||
"sha256:dbaea9e4005a976bcf18fbe2bb87cb9cd0a3f119136f04188ac412d7741cebf0"
|
||||
"sha256:07a95c2f178687fd1c3f722cf792b3d33e3a225ae71577e500c99b28544cd6d0",
|
||||
"sha256:7cadfe900e833857500b7bafa3e5a7eddc3263eb66b66a767870b33e44665f92"
|
||||
],
|
||||
"version": "==8.13.0"
|
||||
"version": "==8.13.1"
|
||||
},
|
||||
"prometheus-client": {
|
||||
"hashes": [
|
||||
@@ -1048,11 +1048,11 @@
|
||||
},
|
||||
"setuptools": {
|
||||
"hashes": [
|
||||
"sha256:6211d2f5eddad8757bd0484923ca7c0a6302ebc4ab32ea5e94357176e0ca0840",
|
||||
"sha256:d1eebf881c6114e51df1664bc2c9133d022f78d12d5f4f665b9191f084e2862d"
|
||||
"sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54",
|
||||
"sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==65.6.0"
|
||||
"version": "==65.6.3"
|
||||
},
|
||||
"shapely": {
|
||||
"hashes": [
|
||||
@@ -1187,11 +1187,11 @@
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e",
|
||||
"sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"
|
||||
"sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc",
|
||||
"sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'",
|
||||
"version": "==1.26.12"
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.26.13"
|
||||
},
|
||||
"vine": {
|
||||
"hashes": [
|
||||
@@ -1302,11 +1302,11 @@
|
||||
},
|
||||
"zipp": {
|
||||
"hashes": [
|
||||
"sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1",
|
||||
"sha256:7a7262fd930bd3e36c50b9a64897aec3fafff3dfdeec9623ae22b40e93f99bb8"
|
||||
"sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa",
|
||||
"sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.10.0"
|
||||
"version": "==3.11.0"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
@@ -1493,43 +1493,43 @@
|
||||
},
|
||||
"cryptography": {
|
||||
"hashes": [
|
||||
"sha256:068147f32fa662c81aebab95c74679b401b12b57494872886eb5c1139250ec5d",
|
||||
"sha256:06fc3cc7b6f6cca87bd56ec80a580c88f1da5306f505876a71c8cfa7050257dd",
|
||||
"sha256:25c1d1f19729fb09d42e06b4bf9895212292cb27bb50229f5aa64d039ab29146",
|
||||
"sha256:402852a0aea73833d982cabb6d0c3bb582c15483d29fb7085ef2c42bfa7e38d7",
|
||||
"sha256:4e269dcd9b102c5a3d72be3c45d8ce20377b8076a43cbed6f660a1afe365e436",
|
||||
"sha256:5419a127426084933076132d317911e3c6eb77568a1ce23c3ac1e12d111e61e0",
|
||||
"sha256:554bec92ee7d1e9d10ded2f7e92a5d70c1f74ba9524947c0ba0c850c7b011828",
|
||||
"sha256:5e89468fbd2fcd733b5899333bc54d0d06c80e04cd23d8c6f3e0542358c6060b",
|
||||
"sha256:65535bc550b70bd6271984d9863a37741352b4aad6fb1b3344a54e6950249b55",
|
||||
"sha256:6ab9516b85bebe7aa83f309bacc5f44a61eeb90d0b4ec125d2d003ce41932d36",
|
||||
"sha256:6addc3b6d593cd980989261dc1cce38263c76954d758c3c94de51f1e010c9a50",
|
||||
"sha256:728f2694fa743a996d7784a6194da430f197d5c58e2f4e278612b359f455e4a2",
|
||||
"sha256:785e4056b5a8b28f05a533fab69febf5004458e20dad7e2e13a3120d8ecec75a",
|
||||
"sha256:78cf5eefac2b52c10398a42765bfa981ce2372cbc0457e6bf9658f41ec3c41d8",
|
||||
"sha256:7f836217000342d448e1c9a342e9163149e45d5b5eca76a30e84503a5a96cab0",
|
||||
"sha256:8d41a46251bf0634e21fac50ffd643216ccecfaf3701a063257fe0b2be1b6548",
|
||||
"sha256:984fe150f350a3c91e84de405fe49e688aa6092b3525f407a18b9646f6612320",
|
||||
"sha256:9b24bcff7853ed18a63cfb0c2b008936a9554af24af2fb146e16d8e1aed75748",
|
||||
"sha256:b1b35d9d3a65542ed2e9d90115dfd16bbc027b3f07ee3304fc83580f26e43249",
|
||||
"sha256:b1b52c9e5f8aa2b802d48bd693190341fae201ea51c7a167d69fc48b60e8a959",
|
||||
"sha256:bbf203f1a814007ce24bd4d51362991d5cb90ba0c177a9c08825f2cc304d871f",
|
||||
"sha256:be243c7e2bfcf6cc4cb350c0d5cdf15ca6383bbcb2a8ef51d3c9411a9d4386f0",
|
||||
"sha256:bfbe6ee19615b07a98b1d2287d6a6073f734735b49ee45b11324d85efc4d5cbd",
|
||||
"sha256:c46837ea467ed1efea562bbeb543994c2d1f6e800785bd5a2c98bc096f5cb220",
|
||||
"sha256:dfb4f4dd568de1b6af9f4cda334adf7d72cf5bc052516e1b2608b683375dd95c",
|
||||
"sha256:ed7b00096790213e09eb11c97cc6e2b757f15f3d2f85833cd2d3ec3fe37c1722"
|
||||
"sha256:0e70da4bdff7601b0ef48e6348339e490ebfb0cbe638e083c9c41fb49f00c8bd",
|
||||
"sha256:10652dd7282de17990b88679cb82f832752c4e8237f0c714be518044269415db",
|
||||
"sha256:175c1a818b87c9ac80bb7377f5520b7f31b3ef2a0004e2420319beadedb67290",
|
||||
"sha256:1d7e632804a248103b60b16fb145e8df0bc60eed790ece0d12efe8cd3f3e7744",
|
||||
"sha256:1f13ddda26a04c06eb57119caf27a524ccae20533729f4b1e4a69b54e07035eb",
|
||||
"sha256:2ec2a8714dd005949d4019195d72abed84198d877112abb5a27740e217e0ea8d",
|
||||
"sha256:2fa36a7b2cc0998a3a4d5af26ccb6273f3df133d61da2ba13b3286261e7efb70",
|
||||
"sha256:2fb481682873035600b5502f0015b664abc26466153fab5c6bc92c1ea69d478b",
|
||||
"sha256:3178d46f363d4549b9a76264f41c6948752183b3f587666aff0555ac50fd7876",
|
||||
"sha256:4367da5705922cf7070462e964f66e4ac24162e22ab0a2e9d31f1b270dd78083",
|
||||
"sha256:4eb85075437f0b1fd8cd66c688469a0c4119e0ba855e3fef86691971b887caf6",
|
||||
"sha256:50a1494ed0c3f5b4d07650a68cd6ca62efe8b596ce743a5c94403e6f11bf06c1",
|
||||
"sha256:53049f3379ef05182864d13bb9686657659407148f901f3f1eee57a733fb4b00",
|
||||
"sha256:6391e59ebe7c62d9902c24a4d8bcbc79a68e7c4ab65863536127c8a9cd94043b",
|
||||
"sha256:67461b5ebca2e4c2ab991733f8ab637a7265bb582f07c7c88914b5afb88cb95b",
|
||||
"sha256:78e47e28ddc4ace41dd38c42e6feecfdadf9c3be2af389abbfeef1ff06822285",
|
||||
"sha256:80ca53981ceeb3241998443c4964a387771588c4e4a5d92735a493af868294f9",
|
||||
"sha256:8a4b2bdb68a447fadebfd7d24855758fe2d6fecc7fed0b78d190b1af39a8e3b0",
|
||||
"sha256:8e45653fb97eb2f20b8c96f9cd2b3a0654d742b47d638cf2897afbd97f80fa6d",
|
||||
"sha256:998cd19189d8a747b226d24c0207fdaa1e6658a1d3f2494541cb9dfbf7dcb6d2",
|
||||
"sha256:a10498349d4c8eab7357a8f9aa3463791292845b79597ad1b98a543686fb1ec8",
|
||||
"sha256:b4cad0cea995af760f82820ab4ca54e5471fc782f70a007f31531957f43e9dee",
|
||||
"sha256:bfe6472507986613dc6cc00b3d492b2f7564b02b3b3682d25ca7f40fa3fd321b",
|
||||
"sha256:c9e0d79ee4c56d841bd4ac6e7697c8ff3c8d6da67379057f29e66acffcd1e9a7",
|
||||
"sha256:ca57eb3ddaccd1112c18fc80abe41db443cc2e9dcb1917078e02dfa010a4f353",
|
||||
"sha256:ce127dd0a6a0811c251a6cddd014d292728484e530d80e872ad9806cfb1c5b3c"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==38.0.3"
|
||||
"version": "==38.0.4"
|
||||
},
|
||||
"cyclonedx-python-lib": {
|
||||
"hashes": [
|
||||
"sha256:39e9d36347d4dc736474ab4f3a7cd7bc91050c9315df698f83a6d8bbcb290744",
|
||||
"sha256:3c79f32bb7d6ed34eac3308dbc8f2a77fbd1fd3779991173a147d866eaa7423e"
|
||||
"sha256:48ae942a892e8385f4e0193d2e295a338df9ab864652081406c26f58085d2b35",
|
||||
"sha256:a03b8f79f23aa95d37180b5d7bca81ef393b569e2d29e02f4817cfe4488e1ba2"
|
||||
],
|
||||
"markers": "python_version >= '3.6' and python_version < '4.0'",
|
||||
"version": "==3.1.0"
|
||||
"version": "==3.1.1"
|
||||
},
|
||||
"execnet": {
|
||||
"hashes": [
|
||||
@@ -1565,11 +1565,11 @@
|
||||
},
|
||||
"gitdb": {
|
||||
"hashes": [
|
||||
"sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd",
|
||||
"sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"
|
||||
"sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a",
|
||||
"sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==4.0.9"
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==4.0.10"
|
||||
},
|
||||
"gitpython": {
|
||||
"hashes": [
|
||||
@@ -1811,11 +1811,11 @@
|
||||
},
|
||||
"pip-audit": {
|
||||
"hashes": [
|
||||
"sha256:00ebef2a52884627f255b879135e28001de4378b8005318b66cc3a802459ee0a",
|
||||
"sha256:d6d830bdbe3fd3efaf54f4a203451f286e75aecb7e44f9f84f7bfbd38aba26ac"
|
||||
"sha256:a99f825ee431a89b89981c4e9e6eaacff5af3233783f2f5d79fe03306dc378ce",
|
||||
"sha256:f87b37b6db5317a3f5ecebc202b5d4401958b5e4bd05b39d7b230bdc6f63c34b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.4.6"
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pip-requirements-parser": {
|
||||
"hashes": [
|
||||
@@ -2026,11 +2026,11 @@
|
||||
},
|
||||
"setuptools": {
|
||||
"hashes": [
|
||||
"sha256:6211d2f5eddad8757bd0484923ca7c0a6302ebc4ab32ea5e94357176e0ca0840",
|
||||
"sha256:d1eebf881c6114e51df1664bc2c9133d022f78d12d5f4f665b9191f084e2862d"
|
||||
"sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54",
|
||||
"sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==65.6.0"
|
||||
"version": "==65.6.3"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
@@ -2088,11 +2088,11 @@
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e",
|
||||
"sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"
|
||||
"sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc",
|
||||
"sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'",
|
||||
"version": "==1.26.12"
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.26.13"
|
||||
},
|
||||
"webencodings": {
|
||||
"hashes": [
|
||||
|
||||
@@ -32,13 +32,11 @@ from app.dao.jobs_dao import (
|
||||
from app.dao.notifications_dao import (
|
||||
dao_old_letters_with_created_status,
|
||||
dao_precompiled_letters_still_pending_virus_check,
|
||||
is_delivery_slow_for_providers,
|
||||
letters_missing_from_sending_bucket,
|
||||
notifications_not_yet_sent,
|
||||
)
|
||||
from app.dao.provider_details_dao import (
|
||||
dao_adjust_provider_priority_back_to_resting_points,
|
||||
dao_reduce_sms_provider_priority,
|
||||
)
|
||||
from app.dao.services_dao import (
|
||||
dao_find_services_sending_to_tv_numbers,
|
||||
@@ -95,28 +93,6 @@ def delete_invitations():
|
||||
raise
|
||||
|
||||
|
||||
@notify_celery.task(name='switch-current-sms-provider-on-slow-delivery')
|
||||
def switch_current_sms_provider_on_slow_delivery():
|
||||
"""
|
||||
Reduce provider's priority if at least 30% of notifications took more than four minutes to be delivered
|
||||
in the last ten minutes. If both providers are slow, don't do anything. If we changed the providers in the
|
||||
last ten minutes, then don't update them again either.
|
||||
"""
|
||||
slow_delivery_notifications = is_delivery_slow_for_providers(
|
||||
threshold=0.3,
|
||||
created_at=datetime.utcnow() - timedelta(minutes=10),
|
||||
delivery_time=timedelta(minutes=4),
|
||||
)
|
||||
|
||||
# only adjust if some values are true and some are false - ie, don't adjust if all providers are fast or
|
||||
# all providers are slow
|
||||
if len(set(slow_delivery_notifications.values())) != 1:
|
||||
for provider_name, is_slow in slow_delivery_notifications.items():
|
||||
if is_slow:
|
||||
current_app.logger.warning('Slow delivery notifications detected for provider {}'.format(provider_name))
|
||||
dao_reduce_sms_provider_priority(provider_name, time_threshold=timedelta(minutes=10))
|
||||
|
||||
|
||||
@notify_celery.task(name='tend-providers-back-to-middle')
|
||||
def tend_providers_back_to_middle():
|
||||
dao_adjust_provider_priority_back_to_resting_points()
|
||||
|
||||
@@ -122,8 +122,9 @@ class Config(object):
|
||||
FIRETEXT_INTERNATIONAL_API_KEY = getenv("FIRETEXT_INTERNATIONAL_API_KEY", "placeholder")
|
||||
# these should always add up to 100%
|
||||
SMS_PROVIDER_RESTING_POINTS = {
|
||||
'mmg': 50,
|
||||
'firetext': 50
|
||||
'sns': 100,
|
||||
'mmg': 0,
|
||||
'firetext': 0
|
||||
}
|
||||
FIRETEXT_INBOUND_SMS_AUTH = json.loads(getenv('FIRETEXT_INBOUND_SMS_AUTH', '[]'))
|
||||
MMG_INBOUND_SMS_AUTH = json.loads(getenv('MMG_INBOUND_SMS_AUTH', '[]'))
|
||||
@@ -215,11 +216,6 @@ class Config(object):
|
||||
'schedule': timedelta(minutes=66),
|
||||
'options': {'queue': QueueNames.PERIODIC}
|
||||
},
|
||||
'switch-current-sms-provider-on-slow-delivery': {
|
||||
'task': 'switch-current-sms-provider-on-slow-delivery',
|
||||
'schedule': crontab(), # Every minute
|
||||
'options': {'queue': QueueNames.PERIODIC}
|
||||
},
|
||||
'check-job-status': {
|
||||
'task': 'check-job-status',
|
||||
'schedule': crontab(),
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
from datetime import datetime, timedelta
|
||||
from itertools import groupby
|
||||
from operator import attrgetter
|
||||
|
||||
from botocore.exceptions import ClientError
|
||||
from flask import current_app
|
||||
@@ -16,14 +14,14 @@ from notifications_utils.timezones import (
|
||||
convert_local_timezone_to_utc,
|
||||
convert_utc_to_local_timezone,
|
||||
)
|
||||
from sqlalchemy import and_, asc, desc, func, or_, union
|
||||
from sqlalchemy import asc, desc, func, or_, union
|
||||
from sqlalchemy.orm import joinedload
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
from sqlalchemy.sql import functions
|
||||
from sqlalchemy.sql.expression import case
|
||||
from werkzeug.datastructures import MultiDict
|
||||
|
||||
from app import create_uuid, db, statsd_client
|
||||
from app import create_uuid, db
|
||||
from app.dao.dao_utils import autocommit
|
||||
from app.letters.utils import LetterPDFNotFound, find_letter_pdf_in_s3
|
||||
from app.models import (
|
||||
@@ -32,7 +30,6 @@ from app.models import (
|
||||
KEY_TYPE_TEST,
|
||||
LETTER_TYPE,
|
||||
NOTIFICATION_CREATED,
|
||||
NOTIFICATION_DELIVERED,
|
||||
NOTIFICATION_PENDING,
|
||||
NOTIFICATION_PENDING_VIRUS_CHECK,
|
||||
NOTIFICATION_PERMANENT_FAILURE,
|
||||
@@ -44,7 +41,6 @@ from app.models import (
|
||||
FactNotificationStatus,
|
||||
Notification,
|
||||
NotificationHistory,
|
||||
ProviderDetails,
|
||||
)
|
||||
from app.utils import (
|
||||
escape_special_characters,
|
||||
@@ -453,61 +449,6 @@ def dao_timeout_notifications(cutoff_time, limit=100000):
|
||||
return notifications
|
||||
|
||||
|
||||
def is_delivery_slow_for_providers(
|
||||
created_at,
|
||||
threshold,
|
||||
delivery_time,
|
||||
):
|
||||
"""
|
||||
Returns a dict of providers and whether they are currently slow or not. eg:
|
||||
{
|
||||
'mmg': True,
|
||||
'firetext': False
|
||||
}
|
||||
"""
|
||||
slow_notification_counts = db.session.query(
|
||||
ProviderDetails.identifier,
|
||||
case(
|
||||
[(
|
||||
Notification.status == NOTIFICATION_DELIVERED,
|
||||
(Notification.updated_at - Notification.sent_at) >= delivery_time
|
||||
)],
|
||||
else_=(datetime.utcnow() - Notification.sent_at) >= delivery_time
|
||||
).label("slow"),
|
||||
func.count().label('count')
|
||||
).select_from(
|
||||
ProviderDetails
|
||||
).outerjoin(
|
||||
Notification, and_(
|
||||
Notification.notification_type == SMS_TYPE,
|
||||
Notification.sent_by == ProviderDetails.identifier,
|
||||
Notification.created_at >= created_at,
|
||||
Notification.sent_at.isnot(None),
|
||||
Notification.status.in_([NOTIFICATION_DELIVERED, NOTIFICATION_PENDING, NOTIFICATION_SENDING]),
|
||||
Notification.key_type != KEY_TYPE_TEST
|
||||
)
|
||||
).filter(
|
||||
ProviderDetails.notification_type == 'sms',
|
||||
ProviderDetails.active
|
||||
).order_by(
|
||||
ProviderDetails.identifier
|
||||
).group_by(
|
||||
ProviderDetails.identifier,
|
||||
"slow"
|
||||
)
|
||||
|
||||
slow_providers = {}
|
||||
for provider, rows in groupby(slow_notification_counts, key=attrgetter('identifier')):
|
||||
rows = list(rows)
|
||||
total_notifications = sum(row.count for row in rows)
|
||||
slow_notifications = sum(row.count for row in rows if row.slow)
|
||||
|
||||
slow_providers[provider] = (slow_notifications / total_notifications >= threshold)
|
||||
statsd_client.gauge(f'slow-delivery.{provider}.ratio', slow_notifications / total_notifications)
|
||||
|
||||
return slow_providers
|
||||
|
||||
|
||||
@autocommit
|
||||
def dao_update_notifications_by_reference(references, update_dict):
|
||||
updated_count = Notification.query.filter(
|
||||
|
||||
@@ -20,11 +20,9 @@ from app.celery.scheduled_tasks import (
|
||||
delete_verify_codes,
|
||||
replay_created_notifications,
|
||||
run_scheduled_jobs,
|
||||
switch_current_sms_provider_on_slow_delivery,
|
||||
)
|
||||
from app.config import QueueNames, TaskNames, Test
|
||||
from app.dao.jobs_dao import dao_get_job_by_id
|
||||
from app.dao.provider_details_dao import get_provider_details_by_identifier
|
||||
from app.models import (
|
||||
JOB_STATUS_ERROR,
|
||||
JOB_STATUS_FINISHED,
|
||||
@@ -37,19 +35,6 @@ from tests.app import load_example_csv
|
||||
from tests.app.db import create_job, create_notification, create_template
|
||||
|
||||
|
||||
def _create_slow_delivery_notification(template, provider='mmg'):
|
||||
now = datetime.utcnow()
|
||||
five_minutes_from_now = now + timedelta(minutes=5)
|
||||
|
||||
create_notification(
|
||||
template=template,
|
||||
status='delivered',
|
||||
sent_by=provider,
|
||||
updated_at=five_minutes_from_now,
|
||||
sent_at=now,
|
||||
)
|
||||
|
||||
|
||||
def test_should_call_delete_codes_on_delete_verify_codes_task(notify_db_session, mocker):
|
||||
mocker.patch('app.celery.scheduled_tasks.delete_codes_older_created_more_than_a_day_ago')
|
||||
delete_verify_codes()
|
||||
@@ -98,47 +83,6 @@ def test_should_update_all_scheduled_jobs_and_put_on_queue(sample_template, mock
|
||||
])
|
||||
|
||||
|
||||
@freeze_time('2017-05-01 14:00:00')
|
||||
def test_switch_current_sms_provider_on_slow_delivery_switches_when_one_provider_is_slow(
|
||||
mocker,
|
||||
restore_provider_details,
|
||||
):
|
||||
is_slow_dict = {'mmg': False, 'firetext': True}
|
||||
mock_is_slow = mocker.patch('app.celery.scheduled_tasks.is_delivery_slow_for_providers', return_value=is_slow_dict)
|
||||
mock_reduce = mocker.patch('app.celery.scheduled_tasks.dao_reduce_sms_provider_priority')
|
||||
# updated_at times are older than the 10 minute window
|
||||
get_provider_details_by_identifier('mmg').updated_at = datetime(2017, 5, 1, 13, 49)
|
||||
get_provider_details_by_identifier('firetext').updated_at = None
|
||||
|
||||
switch_current_sms_provider_on_slow_delivery()
|
||||
|
||||
mock_is_slow.assert_called_once_with(
|
||||
threshold=0.3,
|
||||
created_at=datetime(2017, 5, 1, 13, 50),
|
||||
delivery_time=timedelta(minutes=4)
|
||||
)
|
||||
mock_reduce.assert_called_once_with('firetext', time_threshold=timedelta(minutes=10))
|
||||
|
||||
|
||||
@freeze_time('2017-05-01 14:00:00')
|
||||
@pytest.mark.parametrize('is_slow_dict', [
|
||||
{'mmg': False, 'firetext': False},
|
||||
{'mmg': True, 'firetext': True},
|
||||
])
|
||||
def test_switch_current_sms_provider_on_slow_delivery_does_nothing_if_no_need(
|
||||
mocker,
|
||||
restore_provider_details,
|
||||
is_slow_dict
|
||||
):
|
||||
mocker.patch('app.celery.scheduled_tasks.is_delivery_slow_for_providers', return_value=is_slow_dict)
|
||||
mock_reduce = mocker.patch('app.celery.scheduled_tasks.dao_reduce_sms_provider_priority')
|
||||
get_provider_details_by_identifier('mmg').updated_at = datetime(2017, 5, 1, 13, 51)
|
||||
|
||||
switch_current_sms_provider_on_slow_delivery()
|
||||
|
||||
assert mock_reduce.called is False
|
||||
|
||||
|
||||
def test_check_job_status_task_calls_process_incomplete_jobs(mocker, sample_template):
|
||||
mock_celery = mocker.patch('app.celery.tasks.process_incomplete_jobs.apply_async')
|
||||
job = create_job(template=sample_template, notification_count=3,
|
||||
|
||||
@@ -25,7 +25,6 @@ from app.dao.notifications_dao import (
|
||||
get_notifications_for_job,
|
||||
get_notifications_for_service,
|
||||
get_service_ids_with_notifications_on_date,
|
||||
is_delivery_slow_for_providers,
|
||||
notifications_not_yet_sent,
|
||||
update_notification_status_by_id,
|
||||
update_notification_status_by_reference,
|
||||
@@ -36,12 +35,9 @@ from app.models import (
|
||||
KEY_TYPE_TEAM,
|
||||
KEY_TYPE_TEST,
|
||||
NOTIFICATION_DELIVERED,
|
||||
NOTIFICATION_PENDING,
|
||||
NOTIFICATION_SENDING,
|
||||
NOTIFICATION_SENT,
|
||||
NOTIFICATION_STATUS_TYPES,
|
||||
NOTIFICATION_STATUS_TYPES_FAILED,
|
||||
NOTIFICATION_TEMPORARY_FAILURE,
|
||||
SMS_TYPE,
|
||||
Job,
|
||||
Notification,
|
||||
@@ -928,95 +924,6 @@ def test_should_exclude_test_key_notifications_by_default(
|
||||
assert len(all_notifications) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"normal_sending,slow_sending,normal_delivered,slow_delivered,threshold,expected_result",
|
||||
[
|
||||
(0, 0, 0, 0, 0.1, False),
|
||||
(1, 0, 0, 0, 0.1, False),
|
||||
(1, 1, 0, 0, 0.1, True),
|
||||
(0, 0, 1, 1, 0.1, True),
|
||||
(1, 1, 1, 1, 0.5, True),
|
||||
(1, 1, 1, 1, 0.6, False),
|
||||
(45, 5, 45, 5, 0.1, True),
|
||||
]
|
||||
)
|
||||
@freeze_time("2018-12-04 12:00:00.000000")
|
||||
def test_is_delivery_slow_for_providers(
|
||||
notify_db_session,
|
||||
sample_template,
|
||||
normal_sending,
|
||||
slow_sending,
|
||||
normal_delivered,
|
||||
slow_delivered,
|
||||
threshold,
|
||||
expected_result
|
||||
):
|
||||
normal_notification = partial(
|
||||
create_notification,
|
||||
template=sample_template,
|
||||
sent_by='sns',
|
||||
sent_at=datetime.now(),
|
||||
updated_at=datetime.now()
|
||||
)
|
||||
|
||||
slow_notification = partial(
|
||||
create_notification,
|
||||
template=sample_template,
|
||||
sent_by='sns',
|
||||
sent_at=datetime.now() - timedelta(minutes=5),
|
||||
updated_at=datetime.now()
|
||||
)
|
||||
|
||||
for _ in range(normal_sending):
|
||||
normal_notification(status='sending')
|
||||
for _ in range(slow_sending):
|
||||
slow_notification(status='sending')
|
||||
for _ in range(normal_delivered):
|
||||
normal_notification(status='delivered')
|
||||
for _ in range(slow_delivered):
|
||||
slow_notification(status='delivered')
|
||||
|
||||
result = is_delivery_slow_for_providers(datetime.utcnow(), threshold, timedelta(minutes=4))
|
||||
assert result == {
|
||||
'firetext': False,
|
||||
'mmg': False,
|
||||
'sns': expected_result
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Needs updating for TTS: Failing for unknown reason")
|
||||
@pytest.mark.parametrize("options,expected_result", [
|
||||
({"status": NOTIFICATION_DELIVERED, "sent_by": "mmg"}, True),
|
||||
({"status": NOTIFICATION_PENDING, "sent_by": "mmg"}, True),
|
||||
({"status": NOTIFICATION_SENDING, "sent_by": "mmg"}, True),
|
||||
|
||||
({"status": NOTIFICATION_TEMPORARY_FAILURE, "sent_by": "mmg"}, False),
|
||||
({"status": NOTIFICATION_DELIVERED, "sent_by": "mmg", "sent_at": None}, False),
|
||||
({"status": NOTIFICATION_DELIVERED, "sent_by": "mmg", "key_type": KEY_TYPE_TEST}, False),
|
||||
({"status": NOTIFICATION_SENDING, "sent_by": "firetext"}, False),
|
||||
({"status": NOTIFICATION_DELIVERED, "sent_by": "firetext"}, False),
|
||||
|
||||
])
|
||||
@freeze_time("2018-12-04 12:00:00.000000")
|
||||
def test_delivery_is_delivery_slow_for_providers_filters_out_notifications_it_should_not_count(
|
||||
notify_db_session,
|
||||
sample_template,
|
||||
options,
|
||||
expected_result
|
||||
):
|
||||
create_slow_notification_with = {
|
||||
"template": sample_template,
|
||||
"sent_at": datetime.now() - timedelta(minutes=5),
|
||||
"updated_at": datetime.now(),
|
||||
}
|
||||
create_slow_notification_with.update(options)
|
||||
create_notification(
|
||||
**create_slow_notification_with
|
||||
)
|
||||
result = is_delivery_slow_for_providers(datetime.utcnow(), 0.1, timedelta(minutes=4))
|
||||
assert result['mmg'] == expected_result
|
||||
|
||||
|
||||
def test_dao_get_notifications_by_recipient(sample_template):
|
||||
|
||||
recipient_to_search_for = {
|
||||
|
||||
Reference in New Issue
Block a user