remove letters from app/celery

This commit is contained in:
stvnrlly
2022-12-07 22:04:36 -05:00
parent 90f3dde344
commit 42447fcb8c
6 changed files with 3 additions and 397 deletions

View File

@@ -12,7 +12,7 @@ from app.dao.fact_billing_dao import (
)
from app.dao.fact_notification_status_dao import update_fact_notification_status
from app.dao.notifications_dao import get_service_ids_with_notifications_on_date
from app.models import EMAIL_TYPE, LETTER_TYPE, SMS_TYPE
from app.models import EMAIL_TYPE, SMS_TYPE
@notify_celery.task(name="create-nightly-billing")
@@ -72,10 +72,6 @@ def create_nightly_notification_status():
because all outstanding email / SMS are "timed out" after 3 days, and
we reject delivery receipts after this point.
- Letter statuses don't change after 9 days. There's no "timeout" for
letters but this is the longest we've had to cope with in the past - due
to major issues with our print provider.
Because the time range of the task exceeds the minimum possible retention
period (3 days), we need to choose which table to query for each service.
@@ -89,8 +85,8 @@ def create_nightly_notification_status():
yesterday = convert_utc_to_local_timezone(datetime.utcnow()).date() - timedelta(days=1)
for notification_type in [SMS_TYPE, EMAIL_TYPE, LETTER_TYPE]:
days = 10 if notification_type == LETTER_TYPE else 4
for notification_type in [SMS_TYPE, EMAIL_TYPE]:
days = 4
for i in range(days):
process_day = yesterday - timedelta(days=i)

View File

@@ -14,10 +14,8 @@ from app.dao.inbound_sms_dao import dao_get_inbound_sms_by_id
from app.dao.jobs_dao import dao_get_job_by_id, dao_update_job
from app.dao.notifications_dao import (
dao_get_last_notification_added_for_job_id,
dao_update_notifications_by_reference,
get_notification_by_id,
)
from app.dao.returned_letters_dao import insert_or_update_returned_letters
from app.dao.service_email_reply_to_dao import dao_get_reply_to_by_id
from app.dao.service_inbound_api_dao import get_service_inbound_api_for_service
from app.dao.service_sms_sender_dao import dao_get_service_sms_senders_by_id
@@ -29,7 +27,6 @@ from app.models import (
JOB_STATUS_IN_PROGRESS,
JOB_STATUS_PENDING,
KEY_TYPE_NORMAL,
NOTIFICATION_RETURNED_LETTER,
SMS_TYPE,
)
from app.notifications.process_notifications import persist_notification
@@ -426,19 +423,3 @@ def process_incomplete_job(job_id):
process_row(row, template, job, job.service, sender_id=sender_id)
job_complete(job, resumed=True)
@notify_celery.task(name='process-returned-letters-list')
def process_returned_letters_list(notification_references):
updated, updated_history = dao_update_notifications_by_reference(
notification_references,
{"status": NOTIFICATION_RETURNED_LETTER}
)
insert_or_update_returned_letters(notification_references)
current_app.logger.info(
"Updated {} letter notifications ({} history notifications, from {} references) to returned-letter".format(
updated, updated_history, len(notification_references)
)
)

View File

@@ -1,10 +1,6 @@
from datetime import datetime
from sqlalchemy import desc, func
from sqlalchemy.dialects.postgresql import insert
from app import db
from app.dao.dao_utils import autocommit
from app.models import (
Job,
Notification,
@@ -16,41 +12,6 @@ from app.models import (
from app.utils import midnight_n_days_ago
def _get_notification_ids_for_references(references):
notification_ids = db.session.query(Notification.id, Notification.service_id).filter(
Notification.reference.in_(references)
).all()
notification_history_ids = db.session.query(NotificationHistory.id, NotificationHistory.service_id).filter(
NotificationHistory.reference.in_(references)
).all()
return notification_ids + notification_history_ids
@autocommit
def insert_or_update_returned_letters(references):
data = _get_notification_ids_for_references(references)
for row in data:
table = ReturnedLetter.__table__
stmt = insert(table).values(
reported_at=datetime.utcnow().date(),
service_id=row.service_id,
notification_id=row.id,
created_at=datetime.utcnow()
)
stmt = stmt.on_conflict_do_update(
index_elements=[table.c.notification_id],
set_={
'reported_at': datetime.utcnow().date(),
'updated_at': datetime.utcnow()
}
)
db.session.connection().execute(stmt)
def fetch_recent_returned_letter_count(service_id):
return db.session.query(
func.count(ReturnedLetter.notification_id).label('returned_letter_count'),

View File

@@ -23,7 +23,6 @@ from app.celery.tasks import (
process_incomplete_job,
process_incomplete_jobs,
process_job,
process_returned_letters_list,
process_row,
s3,
save_api_email,
@@ -1363,47 +1362,6 @@ def test_process_incomplete_jobs_sets_status_to_in_progress_and_resets_processin
assert mock_process_incomplete_job.mock_calls == [call(str(job1.id)), call(str(job2.id))]
@pytest.mark.skip(reason="Needs updating for TTS: Remove mail")
def test_process_returned_letters_list(sample_letter_template):
create_notification(sample_letter_template, reference='ref1')
create_notification(sample_letter_template, reference='ref2')
process_returned_letters_list(['ref1', 'ref2', 'unknown-ref'])
notifications = Notification.query.all()
assert [n.status for n in notifications] == ['returned-letter', 'returned-letter']
assert all(n.updated_at for n in notifications)
@pytest.mark.skip(reason="Needs updating for TTS: Remove mail")
def test_process_returned_letters_list_updates_history_if_notification_is_already_purged(
sample_letter_template
):
create_notification_history(sample_letter_template, reference='ref1')
create_notification_history(sample_letter_template, reference='ref2')
process_returned_letters_list(['ref1', 'ref2', 'unknown-ref'])
notifications = NotificationHistory.query.all()
assert [n.status for n in notifications] == ['returned-letter', 'returned-letter']
assert all(n.updated_at for n in notifications)
@pytest.mark.skip(reason="Needs updating for TTS: Remove mail")
def test_process_returned_letters_populates_returned_letters_table(
sample_letter_template
):
create_notification_history(sample_letter_template, reference='ref1')
create_notification_history(sample_letter_template, reference='ref2')
process_returned_letters_list(['ref1', 'ref2', 'unknown-ref'])
returned_letters = ReturnedLetter.query.all()
assert len(returned_letters) == 2
@freeze_time('2020-03-25 14:30')
@pytest.mark.parametrize('notification_type', ['sms', 'email'])
def test_save_api_email_or_sms(mocker, sample_service, notification_type):

View File

@@ -1,248 +0,0 @@
import uuid
from datetime import date, datetime, timedelta
from freezegun import freeze_time
from app.dao.returned_letters_dao import (
fetch_most_recent_returned_letter,
fetch_recent_returned_letter_count,
fetch_returned_letter_summary,
fetch_returned_letters,
insert_or_update_returned_letters,
)
from app.models import NOTIFICATION_RETURNED_LETTER, ReturnedLetter
from tests.app.db import (
create_notification,
create_notification_history,
create_returned_letter,
create_service,
)
def test_insert_or_update_returned_letters_inserts(sample_letter_template):
notification = create_notification(template=sample_letter_template,
reference='ref1')
history = create_notification_history(template=sample_letter_template,
reference='ref2')
assert ReturnedLetter.query.count() == 0
insert_or_update_returned_letters(['ref1', 'ref2'])
returned_letters = ReturnedLetter.query.all()
assert len(returned_letters) == 2
returned_letters_ = [x.notification_id for x in returned_letters]
assert notification.id in returned_letters_
assert history.id in returned_letters_
def test_insert_or_update_returned_letters_updates(sample_letter_template):
notification = create_notification(template=sample_letter_template,
reference='ref1')
history = create_notification_history(template=sample_letter_template,
reference='ref2')
assert ReturnedLetter.query.count() == 0
with freeze_time('2019-12-09 13:30'):
insert_or_update_returned_letters(['ref1', 'ref2'])
returned_letters = ReturnedLetter.query.all()
assert len(returned_letters) == 2
for x in returned_letters:
assert x.reported_at == date(2019, 12, 9)
assert x.created_at == datetime(2019, 12, 9, 13, 30)
assert not x.updated_at
assert x.notification_id in [notification.id, history.id]
with freeze_time('2019-12-10 14:20'):
insert_or_update_returned_letters(['ref1', 'ref2'])
returned_letters = ReturnedLetter.query.all()
assert len(returned_letters) == 2
for x in returned_letters:
assert x.reported_at == date(2019, 12, 10)
assert x.created_at == datetime(2019, 12, 9, 13, 30)
assert x.updated_at == datetime(2019, 12, 10, 14, 20)
assert x.notification_id in [notification.id, history.id]
def test_insert_or_update_returned_letters_when_no_notification(notify_db_session):
insert_or_update_returned_letters(['ref1'])
assert ReturnedLetter.query.count() == 0
def test_insert_or_update_returned_letters_for_history_only(sample_letter_template):
history_1 = create_notification_history(template=sample_letter_template,
reference='ref1')
history_2 = create_notification_history(template=sample_letter_template,
reference='ref2')
assert ReturnedLetter.query.count() == 0
insert_or_update_returned_letters(['ref1', 'ref2'])
returned_letters = ReturnedLetter.query.all()
assert len(returned_letters) == 2
for x in returned_letters:
assert x.notification_id in [history_1.id, history_2.id]
def test_insert_or_update_returned_letters_with_duplicates_in_reference_list(sample_letter_template):
notification_1 = create_notification(template=sample_letter_template,
reference='ref1')
notification_2 = create_notification(template=sample_letter_template,
reference='ref2')
assert ReturnedLetter.query.count() == 0
insert_or_update_returned_letters(['ref1', 'ref2', 'ref1', 'ref2'])
returned_letters = ReturnedLetter.query.all()
assert len(returned_letters) == 2
for x in returned_letters:
assert x.notification_id in [notification_1.id, notification_2.id]
def test_get_returned_letter_count(sample_service):
# Before 7 days dont count
create_returned_letter(
sample_service,
reported_at=datetime(2001, 1, 1)
)
create_returned_letter(
sample_service,
reported_at=datetime(2010, 11, 1, 23, 59, 59),
)
# In the last 7 days count
create_returned_letter(
sample_service,
reported_at=datetime(2010, 11, 2, 0, 0, 0),
)
create_returned_letter(
sample_service,
reported_at=datetime(2010, 11, 8, 10, 0),
)
create_returned_letter(
sample_service,
reported_at=datetime(2010, 11, 8, 10, 0),
)
# Different service dont count
create_returned_letter(
create_service(service_id=uuid.uuid4(), service_name='Other service'),
reported_at=datetime(2010, 11, 8, 10, 0),
)
with freeze_time('2010-11-08 10:10'):
result = fetch_recent_returned_letter_count(sample_service.id)
assert result.returned_letter_count == 3
def test_fetch_most_recent_returned_letter_for_service(sample_service):
# Older
create_returned_letter(
sample_service,
reported_at=datetime(2009, 9, 9, 9, 9),
)
# Newer
create_returned_letter(
sample_service,
reported_at=datetime(2010, 10, 10, 10, 10),
)
# Newest, but different service
create_returned_letter(
create_service(service_id=uuid.uuid4(), service_name='Other service'),
reported_at=datetime(2011, 11, 11, 11, 11),
)
result = fetch_most_recent_returned_letter(sample_service.id)
assert str(result.reported_at) == '2010-10-10'
def test_get_returned_letter_summary(sample_service):
now = datetime.utcnow()
create_returned_letter(sample_service, reported_at=now)
create_returned_letter(sample_service, reported_at=now)
results = fetch_returned_letter_summary(sample_service.id)
assert len(results) == 1
assert results[0].returned_letter_count == 2
assert results[0].reported_at == now.date()
def test_get_returned_letter_summary_orders_by_reported_at(sample_service):
now = datetime.utcnow()
last_month = datetime.utcnow() - timedelta(days=30)
create_returned_letter(sample_service, reported_at=now)
create_returned_letter(sample_service, reported_at=now)
create_returned_letter(sample_service, reported_at=now)
create_returned_letter(sample_service, reported_at=last_month)
create_returned_letter(sample_service, reported_at=last_month)
create_returned_letter() # returned letter for a different service
results = fetch_returned_letter_summary(sample_service.id)
assert len(results) == 2
assert results[0].reported_at == now.date()
assert results[0].returned_letter_count == 3
assert results[1].reported_at == last_month.date()
assert results[1].returned_letter_count == 2
def test_fetch_returned_letters_from_notifications_and_notification_history(sample_letter_template):
today = datetime.now()
last_month = datetime.now() - timedelta(days=30)
letter_1 = create_notification(template=sample_letter_template, client_reference='letter_1',
status=NOTIFICATION_RETURNED_LETTER,
created_at=datetime.utcnow() - timedelta(days=1))
returned_letter_1 = create_returned_letter(service=sample_letter_template.service, reported_at=today,
notification_id=letter_1.id)
letter_2 = create_notification_history(template=sample_letter_template, client_reference='letter_2',
status=NOTIFICATION_RETURNED_LETTER, created_at=datetime.utcnow())
returned_letter_2 = create_returned_letter(service=sample_letter_template.service, reported_at=today,
notification_id=letter_2.id)
letter_3 = create_notification_history(template=sample_letter_template, client_reference='letter_3',
status=NOTIFICATION_RETURNED_LETTER)
create_returned_letter(service=sample_letter_template.service, reported_at=last_month,
notification_id=letter_3.id)
results = fetch_returned_letters(service_id=sample_letter_template.service_id, report_date=today.date())
assert len(results) == 2
assert results[0] == (letter_2.id, returned_letter_2.reported_at, letter_2.client_reference, letter_2.created_at,
sample_letter_template.name, letter_2.template_id, letter_2.template_version, False, None,
None, None, None, None, None)
assert results[1] == (letter_1.id, returned_letter_1.reported_at, letter_1.client_reference, letter_1.created_at,
sample_letter_template.name, letter_1.template_id, letter_1.template_version, False,
letter_1.api_key_id, None, None, None, None, None)
def test_fetch_returned_letters_with_jobs(sample_letter_job):
today = datetime.now()
letter_1 = create_notification_history(template=sample_letter_job.template, client_reference='letter_1',
status=NOTIFICATION_RETURNED_LETTER,
job=sample_letter_job, job_row_number=20,
created_at=datetime.utcnow() - timedelta(minutes=1))
returned_letter_1 = create_returned_letter(service=sample_letter_job.service, reported_at=today,
notification_id=letter_1.id)
results = fetch_returned_letters(service_id=sample_letter_job.service_id, report_date=today.date())
assert len(results) == 1
assert results[0] == (letter_1.id, returned_letter_1.reported_at, letter_1.client_reference, letter_1.created_at,
sample_letter_job.template.name, letter_1.template_id, letter_1.template_version, False, None,
None, None, None, sample_letter_job.original_file_name, 21)
def test_fetch_returned_letters_with_create_by_user(sample_letter_template):
today = datetime.now()
letter_1 = create_notification_history(template=sample_letter_template, client_reference='letter_1',
status=NOTIFICATION_RETURNED_LETTER,
created_at=datetime.utcnow() - timedelta(minutes=1),
created_by_id=sample_letter_template.service.users[0].id)
returned_letter_1 = create_returned_letter(service=sample_letter_template.service, reported_at=today,
notification_id=letter_1.id)
results = fetch_returned_letters(service_id=sample_letter_template.service_id, report_date=today.date())
assert len(results) == 1
assert results[0] == (letter_1.id, returned_letter_1.reported_at, letter_1.client_reference, letter_1.created_at,
sample_letter_template.name, letter_1.template_id, letter_1.template_version, False, None,
letter_1.created_by_id, sample_letter_template.service.users[0].name,
sample_letter_template.service.users[0].email_address, None, None)

View File

@@ -1,42 +0,0 @@
import pytest
@pytest.mark.parametrize('status, references', [
(200, ["1234567890ABCDEF", "1234567890ABCDEG"]),
(400, ["1234567890ABCDEFG", "1234567890ABCDEG"]),
(400, ["1234567890ABCDE", "1234567890ABCDEG"]),
(400, ["1234567890ABCDE\u26d4", "1234567890ABCDEG"]),
(400, ["NOTIFY0001234567890ABCDEF", "1234567890ABCDEG"]),
])
def test_process_returned_letters(status, references, admin_request, mocker):
mock_celery = mocker.patch("app.letters.rest.process_returned_letters_list.apply_async")
response = admin_request.post(
'letter-job.create_process_returned_letters_job',
_data={"references": references},
_expected_status=status
)
if status != 200:
assert '{} does not match'.format(references[0]) in response['errors'][0]['message']
else:
mock_celery.assert_called_once_with(args=(references,), queue='database-tasks', compression='zlib')
def test_process_returned_letters_splits_tasks_up(admin_request, mocker):
mock_celery = mocker.patch("app.letters.rest.process_returned_letters_list.apply_async")
mocker.patch("app.letters.rest.MAX_REFERENCES_PER_TASK", 3)
references = [f'{x:016}' for x in range(10)]
admin_request.post(
'letter-job.create_process_returned_letters_job',
_data={"references": references},
)
assert mock_celery.call_count == 4
assert mock_celery.call_args_list[0][1]['args'][0] == ['0000000000000000', '0000000000000001', '0000000000000002']
assert mock_celery.call_args_list[1][1]['args'][0] == ['0000000000000003', '0000000000000004', '0000000000000005']
assert mock_celery.call_args_list[2][1]['args'][0] == ['0000000000000006', '0000000000000007', '0000000000000008']
assert mock_celery.call_args_list[3][1]['args'][0] == ['0000000000000009']