diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index bcd7eec4d..36901aecd 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -23,6 +23,7 @@ from app.models import ( NOTIFICATION_SENDING, NOTIFICATION_PENDING, NOTIFICATION_TECHNICAL_FAILURE, + NOTIFICATION_TEMPORARY_FAILURE, KEY_TYPE_NORMAL, KEY_TYPE_TEST) from app.dao.dao_utils import transactional @@ -349,17 +350,32 @@ def dao_delete_notifications_and_history_by_id(notification_id): def dao_timeout_notifications(timeout_period_in_seconds): # update all notifications that are older that the timeout_period_in_seconds - # with a status of created|sending|pending + # with a status of created|sending|pending + + # Notifications still in created status are marked with a technical-failure: + # the notification has failed to go to the provider update_at = datetime.utcnow() updated = db.session.query(Notification). \ filter(Notification.created_at < (datetime.utcnow() - timedelta(seconds=timeout_period_in_seconds))). \ - filter(Notification.status.in_([NOTIFICATION_CREATED, NOTIFICATION_SENDING, NOTIFICATION_PENDING])). \ + filter(Notification.status == NOTIFICATION_CREATED). \ update({'status': NOTIFICATION_TECHNICAL_FAILURE, 'updated_at': update_at}, synchronize_session=False) db.session.query(NotificationHistory). \ filter(NotificationHistory.created_at < (datetime.utcnow() - timedelta(seconds=timeout_period_in_seconds))). \ - filter(NotificationHistory.status.in_([NOTIFICATION_CREATED, NOTIFICATION_SENDING, NOTIFICATION_PENDING])). \ + filter(NotificationHistory.status == NOTIFICATION_CREATED). \ update({'status': NOTIFICATION_TECHNICAL_FAILURE, 'updated_at': update_at}, synchronize_session=False) + + # Notifications still in sending or pending status are marked with a temporary-failure: + # the notification was sent to the provider but there was not a delivery receipt, try to send again. + updated += db.session.query(Notification). \ + filter(Notification.created_at < (datetime.utcnow() - timedelta(seconds=timeout_period_in_seconds))). \ + filter(Notification.status.in_([NOTIFICATION_SENDING, NOTIFICATION_PENDING])). \ + update({'status': NOTIFICATION_TEMPORARY_FAILURE, 'updated_at': update_at}, synchronize_session=False) + db.session.query(NotificationHistory). \ + filter(NotificationHistory.created_at < (datetime.utcnow() - timedelta(seconds=timeout_period_in_seconds))). \ + filter(NotificationHistory.status.in_([NOTIFICATION_SENDING, NOTIFICATION_PENDING])). \ + update({'status': NOTIFICATION_TEMPORARY_FAILURE, 'updated_at': update_at}, synchronize_session=False) db.session.commit() + return updated diff --git a/tests/app/celery/test_scheduled_tasks.py b/tests/app/celery/test_scheduled_tasks.py index 541c9fb6f..f5f1a44c9 100644 --- a/tests/app/celery/test_scheduled_tasks.py +++ b/tests/app/celery/test_scheduled_tasks.py @@ -66,8 +66,26 @@ def test_update_status_of_notifications_after_timeout(notify_api, status='sending', created_at=datetime.utcnow() - timedelta( seconds=current_app.config.get('SENDING_NOTIFICATIONS_TIMEOUT_PERIOD') + 10)) + not2 = sample_notification( + notify_db, + notify_db_session, + service=sample_service, + template=sample_template, + status='created', + created_at=datetime.utcnow() - timedelta( + seconds=current_app.config.get('SENDING_NOTIFICATIONS_TIMEOUT_PERIOD') + 10)) + not3 = sample_notification( + notify_db, + notify_db_session, + service=sample_service, + template=sample_template, + status='pending', + created_at=datetime.utcnow() - timedelta( + seconds=current_app.config.get('SENDING_NOTIFICATIONS_TIMEOUT_PERIOD') + 10)) timeout_notifications() - assert not1.status == 'technical-failure' + assert not1.status == 'temporary-failure' + assert not2.status == 'technical-failure' + assert not3.status == 'temporary-failure' def test_not_update_status_of_notification_before_timeout(notify_api, diff --git a/tests/app/dao/test_notification_dao.py b/tests/app/dao/test_notification_dao.py index 43c4b0bd1..1ea6b6871 100644 --- a/tests/app/dao/test_notification_dao.py +++ b/tests/app/dao/test_notification_dao.py @@ -949,8 +949,8 @@ def _notification_json(sample_template, job_id=None, id=None, status=None): def test_dao_timeout_notifications(notify_db, notify_db_session, ): - with freeze_time(datetime.utcnow() - timedelta(minutes=1)): - created = sample_notification(notify_db, notify_db_session) + with freeze_time(datetime.utcnow() - timedelta(minutes=2)): + created = sample_notification(notify_db, notify_db_session, status='created') sending = sample_notification(notify_db, notify_db_session, status='sending') pending = sample_notification(notify_db, notify_db_session, status='pending') delivered = sample_notification(notify_db, notify_db_session, status='delivered') @@ -961,19 +961,19 @@ def test_dao_timeout_notifications(notify_db, notify_db_session, ): assert Notification.query.get(delivered.id).status == 'delivered' updated = dao_timeout_notifications(1) assert Notification.query.get(created.id).status == 'technical-failure' - assert Notification.query.get(sending.id).status == 'technical-failure' - assert Notification.query.get(pending.id).status == 'technical-failure' + assert Notification.query.get(sending.id).status == 'temporary-failure' + assert Notification.query.get(pending.id).status == 'temporary-failure' assert Notification.query.get(delivered.id).status == 'delivered' assert NotificationHistory.query.get(created.id).status == 'technical-failure' - assert NotificationHistory.query.get(sending.id).status == 'technical-failure' - assert NotificationHistory.query.get(pending.id).status == 'technical-failure' + 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 def test_dao_timeout_notifications_only_updates_for_older_notifications(notify_db, notify_db_session): with freeze_time(datetime.utcnow() + timedelta(minutes=10)): - created = sample_notification(notify_db, notify_db_session) + created = sample_notification(notify_db, notify_db_session, status='created') sending = sample_notification(notify_db, notify_db_session, status='sending') pending = sample_notification(notify_db, notify_db_session, status='pending') delivered = sample_notification(notify_db, notify_db_session, status='delivered')