From 5ce31c78fdfa4ffbad428f35b17212cb17fd91b0 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 07:30:41 -0800 Subject: [PATCH 01/14] start writing message ids to the notifications table --- app/celery/provider_tasks.py | 4 ++++ app/dao/notifications_dao.py | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/app/celery/provider_tasks.py b/app/celery/provider_tasks.py index 1e6c7e96f..dd95472c9 100644 --- a/app/celery/provider_tasks.py +++ b/app/celery/provider_tasks.py @@ -14,6 +14,7 @@ from app.dao import notifications_dao from app.dao.notifications_dao import ( sanitize_successful_notification_by_id, + update_notification_message_id, update_notification_status_by_id, ) from app.delivery import send_to_providers @@ -128,6 +129,9 @@ def deliver_sms(self, notification_id): ) # Code branches off to send_to_providers.py message_id = send_to_providers.send_sms_to_provider(notification) + update_notification_message_id(notification_id, message_id) + + # DEPRECATED # We have to put it in UTC. For other timezones, the delay # will be ignored and it will fire immediately (although this probably only affects developer testing) my_eta = utc_now() + timedelta(seconds=DELIVERY_RECEIPT_DELAY_IN_SECONDS) diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index 8371aaa85..af3f800e7 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -110,6 +110,16 @@ def _update_notification_status( return notification +@autocommit +def update_notification_message_id(notification_id, message_id): + stmt = ( + update(Notification) + .where(Notification.id == notification_id) + .values({"message_id": message_id}) + ) + db.session.execute(stmt) + + @autocommit def update_notification_status_by_id( notification_id, status, sent_by=None, provider_response=None, carrier=None From 0d280d608a132e7eff4cec0adeb97ac35fd35f0a Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 07:42:08 -0800 Subject: [PATCH 02/14] start writing message ids to the notifications table --- tests/app/celery/test_provider_tasks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/app/celery/test_provider_tasks.py b/tests/app/celery/test_provider_tasks.py index 80d5a0d7e..7923f9498 100644 --- a/tests/app/celery/test_provider_tasks.py +++ b/tests/app/celery/test_provider_tasks.py @@ -131,6 +131,7 @@ def test_should_call_send_sms_to_provider_from_deliver_sms_task( ): mocker.patch("app.delivery.send_to_providers.send_sms_to_provider") mocker.patch("app.celery.provider_tasks.check_sms_delivery_receipt") + mocker.patch("app.celery.provider_tasks.update_notification_message_id") deliver_sms(sample_notification.id) app.delivery.send_to_providers.send_sms_to_provider.assert_called_with( From 26e53a80ba1ecd36868be3bed06a80db45421119 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 08:43:23 -0800 Subject: [PATCH 03/14] avoid message is none scenario --- app/celery/provider_tasks.py | 3 ++- app/dao/notifications_dao.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/celery/provider_tasks.py b/app/celery/provider_tasks.py index dd95472c9..ab8d8435a 100644 --- a/app/celery/provider_tasks.py +++ b/app/celery/provider_tasks.py @@ -129,7 +129,8 @@ def deliver_sms(self, notification_id): ) # Code branches off to send_to_providers.py message_id = send_to_providers.send_sms_to_provider(notification) - update_notification_message_id(notification_id, message_id) + if message_id is not None: # can be none if technical failure happens + update_notification_message_id(notification_id, message_id) # DEPRECATED # We have to put it in UTC. For other timezones, the delay diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index af3f800e7..066c21387 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -110,7 +110,6 @@ def _update_notification_status( return notification -@autocommit def update_notification_message_id(notification_id, message_id): stmt = ( update(Notification) @@ -118,6 +117,7 @@ def update_notification_message_id(notification_id, message_id): .values({"message_id": message_id}) ) db.session.execute(stmt) + db.session.commit() @autocommit From f706086bbf5f4b92d8fb4bdba36d3488574cfd74 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 09:48:48 -0800 Subject: [PATCH 04/14] cleanup --- app/celery/provider_tasks.py | 3 --- app/dao/notifications_dao.py | 2 +- app/delivery/send_to_providers.py | 3 ++- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/celery/provider_tasks.py b/app/celery/provider_tasks.py index ab8d8435a..a75a68c96 100644 --- a/app/celery/provider_tasks.py +++ b/app/celery/provider_tasks.py @@ -14,7 +14,6 @@ from app.dao import notifications_dao from app.dao.notifications_dao import ( sanitize_successful_notification_by_id, - update_notification_message_id, update_notification_status_by_id, ) from app.delivery import send_to_providers @@ -129,8 +128,6 @@ def deliver_sms(self, notification_id): ) # Code branches off to send_to_providers.py message_id = send_to_providers.send_sms_to_provider(notification) - if message_id is not None: # can be none if technical failure happens - update_notification_message_id(notification_id, message_id) # DEPRECATED # We have to put it in UTC. For other timezones, the delay diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index 066c21387..052242644 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -114,7 +114,7 @@ def update_notification_message_id(notification_id, message_id): stmt = ( update(Notification) .where(Notification.id == notification_id) - .values({"message_id": message_id}) + .values(message_id=message_id) ) db.session.execute(stmt) db.session.commit() diff --git a/app/delivery/send_to_providers.py b/app/delivery/send_to_providers.py index 07763823f..4cc57fa6a 100644 --- a/app/delivery/send_to_providers.py +++ b/app/delivery/send_to_providers.py @@ -16,7 +16,7 @@ from app.aws.s3 import get_personalisation_from_s3, get_phone_number_from_s3 from app.celery.test_key_tasks import send_email_response, send_sms_response from app.dao.email_branding_dao import dao_get_email_branding_by_id -from app.dao.notifications_dao import dao_update_notification +from app.dao.notifications_dao import dao_update_notification, update_notification_message_id from app.dao.provider_details_dao import get_provider_details_by_notification_type from app.dao.service_sms_sender_dao import dao_get_sms_senders_by_service_id from app.enums import BrandType, KeyType, NotificationStatus, NotificationType @@ -117,6 +117,7 @@ def send_sms_to_provider(notification): message_id = provider.send_sms(**send_sms_kwargs) current_app.logger.info(f"got message_id {message_id}") + update_notification_message_id(notification.id, message_id) except Exception as e: n = notification msg = f"FAILED send to sms, job_id: {n.job_id} row_number {n.job_row_number} message_id {message_id}" From 6de1b226d0cd01429f6d461537a275c9fc22481e Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 10:15:47 -0800 Subject: [PATCH 05/14] cleanup --- app/delivery/send_to_providers.py | 5 ++++- tests/app/celery/test_provider_tasks.py | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/delivery/send_to_providers.py b/app/delivery/send_to_providers.py index 4cc57fa6a..e41062b41 100644 --- a/app/delivery/send_to_providers.py +++ b/app/delivery/send_to_providers.py @@ -16,7 +16,10 @@ from app.aws.s3 import get_personalisation_from_s3, get_phone_number_from_s3 from app.celery.test_key_tasks import send_email_response, send_sms_response from app.dao.email_branding_dao import dao_get_email_branding_by_id -from app.dao.notifications_dao import dao_update_notification, update_notification_message_id +from app.dao.notifications_dao import ( + dao_update_notification, + update_notification_message_id, +) from app.dao.provider_details_dao import get_provider_details_by_notification_type from app.dao.service_sms_sender_dao import dao_get_sms_senders_by_service_id from app.enums import BrandType, KeyType, NotificationStatus, NotificationType diff --git a/tests/app/celery/test_provider_tasks.py b/tests/app/celery/test_provider_tasks.py index 7923f9498..80d5a0d7e 100644 --- a/tests/app/celery/test_provider_tasks.py +++ b/tests/app/celery/test_provider_tasks.py @@ -131,7 +131,6 @@ def test_should_call_send_sms_to_provider_from_deliver_sms_task( ): mocker.patch("app.delivery.send_to_providers.send_sms_to_provider") mocker.patch("app.celery.provider_tasks.check_sms_delivery_receipt") - mocker.patch("app.celery.provider_tasks.update_notification_message_id") deliver_sms(sample_notification.id) app.delivery.send_to_providers.send_sms_to_provider.assert_called_with( From 674320b72dfb2a8929f7d44e8962cfc49177b858 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 11:54:46 -0800 Subject: [PATCH 06/14] add message_id to model duh --- app/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models.py b/app/models.py index 6b008f64b..ec6eac335 100644 --- a/app/models.py +++ b/app/models.py @@ -1532,6 +1532,7 @@ class Notification(db.Model): provider_response = db.Column(db.Text, nullable=True) carrier = db.Column(db.Text, nullable=True) + message_id = db.Column(db.Text, nullable=True) # queue_name = db.Column(db.Text, nullable=True) From 02c23a29ca5587411c596d924f6680cc538ca504 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 12:12:19 -0800 Subject: [PATCH 07/14] fix tests --- tests/app/delivery/test_send_to_providers.py | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/app/delivery/test_send_to_providers.py b/tests/app/delivery/test_send_to_providers.py index 20b0f7186..672a48734 100644 --- a/tests/app/delivery/test_send_to_providers.py +++ b/tests/app/delivery/test_send_to_providers.py @@ -627,6 +627,10 @@ def test_should_update_billable_units_and_status_according_to_research_mode_and_ ): mocker.patch("app.delivery.send_to_providers.redis_store", return_value=None) + mocker.patch( + "app.delivery.send_to_providers.update_notification_message_id", + return_value=None, + ) mocker.patch( "app.delivery.send_to_providers.get_sender_numbers", return_value=["testing"] ) @@ -637,6 +641,11 @@ def test_should_update_billable_units_and_status_according_to_research_mode_and_ key_type=key_type, reply_to_text="testing", ) + + mocker.patch( + "app.delivery.send_to_providers.update_notification_message_id", + return_value=None, + ) mocker.patch("app.aws_sns_client.send_sms") mocker.patch( "app.delivery.send_to_providers.send_sms_response", @@ -707,6 +716,10 @@ def test_should_send_sms_to_international_providers( mock_s3 = mocker.patch("app.delivery.send_to_providers.get_phone_number_from_s3") mock_s3.return_value = "601117224412" + mocker.patch( + "app.delivery.send_to_providers.update_notification_message_id", + return_value=None, + ) mock_personalisation = mocker.patch( "app.delivery.send_to_providers.get_personalisation_from_s3" ) @@ -744,6 +757,11 @@ def test_should_handle_sms_sender_and_prefix_message( mocker.patch("app.delivery.send_to_providers.redis_store", return_value=None) mocker.patch("app.aws_sns_client.send_sms") + + mocker.patch( + "app.delivery.send_to_providers.update_notification_message_id", + return_value=None, + ) service = create_service_with_defined_sms_sender( sms_sender_value=sms_sender, prefix_sms=prefix_sms ) @@ -803,6 +821,11 @@ def test_send_sms_to_provider_should_use_normalised_to(mocker, client, sample_te mocker.patch( "app.delivery.send_to_providers.get_sender_numbers", return_value=["testing"] ) + + mocker.patch( + "app.delivery.send_to_providers.update_notification_message_id", + return_value=None, + ) send_mock = mocker.patch("app.aws_sns_client.send_sms") notification = create_notification( template=sample_template, @@ -866,6 +889,11 @@ def test_send_sms_to_provider_should_return_template_if_found_in_redis( mocker.patch( "app.delivery.send_to_providers.get_sender_numbers", return_value=["testing"] ) + + mocker.patch( + "app.delivery.send_to_providers.update_notification_message_id", + return_value=None, + ) from app.schemas import service_schema, template_schema service_dict = service_schema.dump(sample_template.service) From d455d6a82998d03382a6630c1f7981f9ffe2c956 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 12:35:19 -0800 Subject: [PATCH 08/14] fix tests --- tests/app/delivery/test_send_to_providers.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/app/delivery/test_send_to_providers.py b/tests/app/delivery/test_send_to_providers.py index 672a48734..585983311 100644 --- a/tests/app/delivery/test_send_to_providers.py +++ b/tests/app/delivery/test_send_to_providers.py @@ -365,6 +365,7 @@ def test_send_sms_should_use_service_sms_sender( mocker.patch("app.delivery.send_to_providers.redis_store", return_value=None) mocker.patch("app.aws_sns_client.send_sms") + mocker.patch("app.delivery.send_to_providers.update_notification_message_id") sms_sender = create_service_sms_sender( service=sample_service, sms_sender="123456", is_default=False @@ -405,6 +406,8 @@ def test_send_email_to_provider_should_not_send_to_provider_when_status_is_not_c ) mocker.patch("app.aws_ses_client.send_email") mocker.patch("app.delivery.send_to_providers.send_email_response") + + mocker.patch("app.delivery.send_to_providers.update_notification_message_id") mock_phone = mocker.patch("app.delivery.send_to_providers.get_phone_number_from_s3") mock_phone.return_value = "15555555555" @@ -656,6 +659,8 @@ def test_should_update_billable_units_and_status_according_to_research_mode_and_ sample_template.service.research_mode = True mock_phone = mocker.patch("app.delivery.send_to_providers.get_phone_number_from_s3") + + mocker.patch("app.delivery.send_to_providers.update_notification_message_id") mock_phone.return_value = "15555555555" mock_personalisation = mocker.patch( @@ -679,6 +684,8 @@ def test_should_set_notification_billable_units_and_reduces_provider_priority_if assert sample_notification.sent_by is None mock_phone = mocker.patch("app.delivery.send_to_providers.get_phone_number_from_s3") + + mocker.patch("app.delivery.send_to_providers.update_notification_message_id") mock_phone.return_value = "15555555555" mock_personalisation = mocker.patch( @@ -714,6 +721,8 @@ def test_should_send_sms_to_international_providers( ) mock_s3 = mocker.patch("app.delivery.send_to_providers.get_phone_number_from_s3") + + mocker.patch("app.delivery.send_to_providers.update_notification_message_id") mock_s3.return_value = "601117224412" mocker.patch( From ee6eded8e40c2e5f752dd6edf15ff3c3409398e7 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 12:46:58 -0800 Subject: [PATCH 09/14] fix tests --- tests/app/delivery/test_send_to_providers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/app/delivery/test_send_to_providers.py b/tests/app/delivery/test_send_to_providers.py index 585983311..7a6259551 100644 --- a/tests/app/delivery/test_send_to_providers.py +++ b/tests/app/delivery/test_send_to_providers.py @@ -93,6 +93,7 @@ def test_should_send_personalised_template_to_correct_sms_provider_and_persist( mock_s3 = mocker.patch("app.delivery.send_to_providers.get_phone_number_from_s3") mock_s3.return_value = "2028675309" + mocker.patch("app.delivery.send_to_providers.update_notification_message_id") mock_personalisation = mocker.patch( "app.delivery.send_to_providers.get_personalisation_from_s3" ) @@ -233,6 +234,7 @@ def test_send_sms_should_use_template_version_from_notification_not_latest( mock_s3 = mocker.patch("app.delivery.send_to_providers.get_phone_number_from_s3") mock_s3.return_value = "2028675309" + mocker.patch("app.delivery.send_to_providers.update_notification_message_id") mock_s3_p = mocker.patch( "app.delivery.send_to_providers.get_personalisation_from_s3" ) @@ -327,6 +329,7 @@ def test_should_send_sms_with_downgraded_content(notify_db_session, mocker): # ī, grapes, tabs, zero width space and ellipsis are not # ó isn't in GSM, but it is in the welsh alphabet so will still be sent + mocker.patch("app.delivery.send_to_providers.update_notification_message_id") mocker.patch("app.delivery.send_to_providers.redis_store", return_value=None) mocker.patch( "app.delivery.send_to_providers.get_sender_numbers", return_value=["testing"] From 020af71574a301206c636923777892307928725e Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 17 Dec 2024 10:50:55 -0800 Subject: [PATCH 10/14] fix census BOM error --- app/aws/s3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws/s3.py b/app/aws/s3.py index e0022f20b..07b53d687 100644 --- a/app/aws/s3.py +++ b/app/aws/s3.py @@ -402,7 +402,7 @@ def extract_phones(job): phone_index = 0 for item in first_row: # Note: may contain a BOM and look like \ufeffphone number - if item.lower() in ["phone number", "\\ufeffphone number"]: + if item.lower() in ["phone number", "\\ufeffphone number", "phone number\n"]: break phone_index = phone_index + 1 From c2d822b2883c8de62e8e3522b07d55adaabd38f7 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 17 Dec 2024 10:56:27 -0800 Subject: [PATCH 11/14] add tests --- app/aws/s3.py | 7 ++++++- tests/app/aws/test_s3.py | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/aws/s3.py b/app/aws/s3.py index 07b53d687..d97c421f2 100644 --- a/app/aws/s3.py +++ b/app/aws/s3.py @@ -402,7 +402,12 @@ def extract_phones(job): phone_index = 0 for item in first_row: # Note: may contain a BOM and look like \ufeffphone number - if item.lower() in ["phone number", "\\ufeffphone number", "phone number\n"]: + if item.lower() in [ + "phone number", + "\\ufeffphone number", + "\\ufeffphone number\n", + "phone number\n", + ]: break phone_index = phone_index + 1 diff --git a/tests/app/aws/test_s3.py b/tests/app/aws/test_s3.py index e4a9c1c07..f9baa2fde 100644 --- a/tests/app/aws/test_s3.py +++ b/tests/app/aws/test_s3.py @@ -219,6 +219,16 @@ def test_get_s3_file_makes_correct_call(notify_api, mocker): 2, "5555555552", ), + ( + # simulate file saved with utf8withbom + "\\ufeffPHONE NUMBER\n", + "5555555552", + ), + ( + # simulate file saved without utf8withbom + "\\PHONE NUMBER\n", + "5555555552", + ), ], ) def test_get_phone_number_from_s3( From 1a5e8824482f128fd641778b30dcb3b1b172c317 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 17 Dec 2024 11:02:40 -0800 Subject: [PATCH 12/14] fix tests --- tests/app/aws/test_s3.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/app/aws/test_s3.py b/tests/app/aws/test_s3.py index f9baa2fde..843ce3ba0 100644 --- a/tests/app/aws/test_s3.py +++ b/tests/app/aws/test_s3.py @@ -222,11 +222,15 @@ def test_get_s3_file_makes_correct_call(notify_api, mocker): ( # simulate file saved with utf8withbom "\\ufeffPHONE NUMBER\n", + "eee", + 2, "5555555552", ), ( # simulate file saved without utf8withbom "\\PHONE NUMBER\n", + "eee", + 2, "5555555552", ), ], From a45e411094c8c88787093def93cedf308b748815 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 18 Dec 2024 11:59:30 -0800 Subject: [PATCH 13/14] stop workers from propagating logs --- app/__init__.py | 4 ++++ notifications_utils/logging.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/app/__init__.py b/app/__init__.py index 16ffbd5a9..23c2399e1 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,3 +1,4 @@ +import logging as real_logging import os import secrets import string @@ -36,6 +37,9 @@ def init_app(self, app): # Configure Celery app with options from the main app config. self.config_from_object(app.config["CELERY"]) + self.conf.worker_hijack_root_logger = False + logger = real_logging.getLogger("celery") + logger.propagate = False def send_task(self, name, args=None, kwargs=None, **other_kwargs): other_kwargs["headers"] = other_kwargs.get("headers") or {} diff --git a/notifications_utils/logging.py b/notifications_utils/logging.py index 0a13555d4..a15d00169 100644 --- a/notifications_utils/logging.py +++ b/notifications_utils/logging.py @@ -70,10 +70,12 @@ def init_app(app): for logger_instance, handler in product(loggers, handlers): logger_instance.addHandler(handler) logger_instance.setLevel(loglevel) + logger_instance.propagate = False warning_loggers = [logging.getLogger("boto3"), logging.getLogger("s3transfer")] for logger_instance, handler in product(warning_loggers, handlers): logger_instance.addHandler(handler) logger_instance.setLevel(logging.WARNING) + logger_instance.propagate = False # Suppress specific loggers to prevent leaking sensitive info logging.getLogger("boto3").setLevel(logging.ERROR) From cfe9b11cf601e75f47852ca6bab8f6492b4f6b2c Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 18 Dec 2024 14:09:22 -0800 Subject: [PATCH 14/14] remove tasks from redis after they complete --- app/celery/tasks.py | 8 ++++++++ app/config.py | 3 +++ 2 files changed, 11 insertions(+) diff --git a/app/celery/tasks.py b/app/celery/tasks.py index b612933ef..c21f4e65c 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -1,5 +1,6 @@ import json +from celery.signals import task_postrun from flask import current_app from requests import HTTPError, RequestException, request from sqlalchemy.exc import IntegrityError, SQLAlchemyError @@ -170,6 +171,13 @@ def __total_sending_limits_for_job_exceeded(service, job, job_id): return True +@task_postrun.connect +def log_task_ejection(sender=None, task_id=None, **kwargs): + current_app.logger.info( + f"Task {task_id} ({sender.name if sender else 'unknown_task'}) has been completed and removed" + ) + + @notify_celery.task(bind=True, name="save-sms", max_retries=2, default_retry_delay=600) def save_sms(self, service_id, notification_id, encrypted_notification, sender_id=None): """Persist notification to db and place notification in queue to send to sns.""" diff --git a/app/config.py b/app/config.py index 12159e289..e8db17ff2 100644 --- a/app/config.py +++ b/app/config.py @@ -168,6 +168,9 @@ class Config(object): CELERY = { "worker_max_tasks_per_child": 500, + "task_ignore_result": True, + "result_expires": 0, + "result_persistent": False, "broker_url": REDIS_URL, "broker_transport_options": { "visibility_timeout": 310,