diff --git a/app/celery/scheduled_tasks.py b/app/celery/scheduled_tasks.py index 697fd2eef..ed14be2e4 100644 --- a/app/celery/scheduled_tasks.py +++ b/app/celery/scheduled_tasks.py @@ -58,6 +58,8 @@ from app.celery.tasks import ( from app.config import QueueNames, TaskNames from app.utils import convert_utc_to_bst from app.v2.errors import JobIncompleteError +from app.dao.service_callback_api_dao import get_service_callback_api_for_service +from app.celery.service_callback_tasks import send_delivery_status_to_service @worker_process_shutdown.connect @@ -189,10 +191,18 @@ def delete_invitations(): @notify_celery.task(name='timeout-sending-notifications') @statsd(namespace="tasks") def timeout_notifications(): - updated = dao_timeout_notifications(current_app.config.get('SENDING_NOTIFICATIONS_TIMEOUT_PERIOD')) - if updated: + notifications = dao_timeout_notifications(current_app.config.get('SENDING_NOTIFICATIONS_TIMEOUT_PERIOD')) + + if notifications: + for notification in notifications: + # queue callback task only if the service_callback_api exists + service_callback_api = get_service_callback_api_for_service(service_id=notification.service_id) + + if service_callback_api: + send_delivery_status_to_service.apply_async([str(id)], queue=QueueNames.NOTIFY) + current_app.logger.info( - "Timeout period reached for {} notifications, status has been updated.".format(updated)) + "Timeout period reached for {} notifications, status has been updated.".format(len(notifications))) @notify_celery.task(name='send-daily-performance-platform-stats') diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index 1f7b33167..d9886fcfd 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -328,17 +328,24 @@ def dao_delete_notifications_and_history_by_id(notification_id): def _timeout_notifications(current_statuses, new_status, timeout_start, updated_at): + + notifications = Notification.query.filter( + Notification.created_at < timeout_start, + Notification.status.in_(current_statuses), + Notification.notification_type != LETTER_TYPE + ).all() for table in [NotificationHistory, Notification]: q = table.query.filter( table.created_at < timeout_start, table.status.in_(current_statuses), table.notification_type != LETTER_TYPE ) - last_update_count = q.update( + q.update( {'status': new_status, 'updated_at': updated_at}, synchronize_session=False ) - return last_update_count + # return a list of q = notification_ids in Notification table for sending delivery receipts + return notifications def dao_timeout_notifications(timeout_period_in_seconds): @@ -359,14 +366,14 @@ def dao_timeout_notifications(timeout_period_in_seconds): timeout = functools.partial(_timeout_notifications, timeout_start=timeout_start, updated_at=updated_at) # Notifications still in created status are marked with a technical-failure: - updated = timeout([NOTIFICATION_CREATED], NOTIFICATION_TECHNICAL_FAILURE) + updated_ids = timeout([NOTIFICATION_CREATED], NOTIFICATION_TECHNICAL_FAILURE) # Notifications still in sending or pending status are marked with a temporary-failure: - updated += timeout([NOTIFICATION_SENDING, NOTIFICATION_PENDING], NOTIFICATION_TEMPORARY_FAILURE) + updated_ids += timeout([NOTIFICATION_SENDING, NOTIFICATION_PENDING], NOTIFICATION_TEMPORARY_FAILURE) db.session.commit() - return updated + return updated_ids def get_total_sent_notifications_in_date_range(start_date, end_date, notification_type): diff --git a/tests/app/dao/notification_dao/test_notification_dao.py b/tests/app/dao/notification_dao/test_notification_dao.py index 0bb9b5322..8af596199 100644 --- a/tests/app/dao/notification_dao/test_notification_dao.py +++ b/tests/app/dao/notification_dao/test_notification_dao.py @@ -1201,7 +1201,7 @@ def test_dao_timeout_notifications(sample_template): assert Notification.query.get(sending.id).status == 'sending' assert Notification.query.get(pending.id).status == 'pending' assert Notification.query.get(delivered.id).status == 'delivered' - updated = dao_timeout_notifications(1) + updated_ids = dao_timeout_notifications(1) assert Notification.query.get(created.id).status == 'technical-failure' assert Notification.query.get(sending.id).status == 'temporary-failure' assert Notification.query.get(pending.id).status == 'temporary-failure' @@ -1210,7 +1210,7 @@ def test_dao_timeout_notifications(sample_template): assert NotificationHistory.query.get(sending.id).status == 'temporary-failure' assert NotificationHistory.query.get(pending.id).status == 'temporary-failure' assert NotificationHistory.query.get(delivered.id).status == 'delivered' - assert updated == 3 + assert len(updated_ids) == 3 def test_dao_timeout_notifications_only_updates_for_older_notifications(sample_template): @@ -1224,12 +1224,12 @@ def test_dao_timeout_notifications_only_updates_for_older_notifications(sample_t assert Notification.query.get(sending.id).status == 'sending' assert Notification.query.get(pending.id).status == 'pending' assert Notification.query.get(delivered.id).status == 'delivered' - updated = dao_timeout_notifications(1) + updated_ids = dao_timeout_notifications(1) assert NotificationHistory.query.get(created.id).status == 'created' assert NotificationHistory.query.get(sending.id).status == 'sending' assert NotificationHistory.query.get(pending.id).status == 'pending' assert NotificationHistory.query.get(delivered.id).status == 'delivered' - assert updated == 0 + assert len(updated_ids) == 0 def test_dao_timeout_notifications_doesnt_affect_letters(sample_letter_template): @@ -1244,13 +1244,13 @@ def test_dao_timeout_notifications_doesnt_affect_letters(sample_letter_template) assert Notification.query.get(pending.id).status == 'pending' assert Notification.query.get(delivered.id).status == 'delivered' - updated = dao_timeout_notifications(1) + updated_ids = dao_timeout_notifications(1) assert NotificationHistory.query.get(created.id).status == 'created' assert NotificationHistory.query.get(sending.id).status == 'sending' assert NotificationHistory.query.get(pending.id).status == 'pending' assert NotificationHistory.query.get(delivered.id).status == 'delivered' - assert updated == 0 + assert len(updated_ids) == 0 def test_should_return_notifications_excluding_jobs_by_default(sample_template, sample_job, sample_api_key):