From 65165ee0dee1ccc70328465c80b05858e379be41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Mart=C3=ADn?= Date: Tue, 3 Jun 2025 16:13:04 +0200 Subject: [PATCH] Add APNS timeout --- README.rst | 1 + push_notifications/apns_async.py | 9 ++++++--- push_notifications/conf/app.py | 6 +++++- push_notifications/conf/legacy.py | 3 +++ push_notifications/settings.py | 1 + 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 81650929..1917d5e6 100644 --- a/README.rst +++ b/README.rst @@ -114,6 +114,7 @@ For WNS, you need both the ``WNS_PACKAGE_SECURITY_KEY`` and the ``WNS_SECRET_KEY - ``APNS_TOPIC``: The topic of the remote notification, which is typically the bundle ID for your app. If you omit this header and your APNs certificate does not specify multiple topics, the APNs server uses the certificate’s Subject as the default topic. - ``APNS_USE_ALTERNATIVE_PORT``: Use port 2197 for APNS, instead of default port 443. - ``APNS_USE_SANDBOX``: Use 'api.development.push.apple.com', instead of default host 'api.push.apple.com'. Default value depends on ``DEBUG`` setting of your environment: if ``DEBUG`` is True and you use production certificate, you should explicitly set ``APNS_USE_SANDBOX`` to False. +- ``APNS_ERROR_TIMEOUT``: The timeout on APNS requests. (Optional, default value is 1 second) **FCM/GCM settings** diff --git a/push_notifications/apns_async.py b/push_notifications/apns_async.py index bf6f3b29..04fc78d4 100644 --- a/push_notifications/apns_async.py +++ b/push_notifications/apns_async.py @@ -317,6 +317,7 @@ def apns_send_bulk_message( """ try: topic = get_manager().get_apns_topic(application_id) + timeout = get_manager().get_apns_error_timeout(application_id) results: Dict[str, str] = {} inactive_tokens = [] @@ -339,6 +340,7 @@ def apns_send_bulk_message( mutable_content=mutable_content, category=category, err_func=err_func, + timeout=timeout, ) ) @@ -390,6 +392,7 @@ async def _send_bulk_request( mutable_content: bool = False, category: str = None, err_func: ErrFunc = None, + timeout: float = None, ): client = _create_client( creds=creds, application_id=application_id, topic=topic, err_func=err_func @@ -420,13 +423,13 @@ async def _send_bulk_request( for registration_id in registration_ids ] - send_requests = [_send_request(client, request) for request in requests] + send_requests = [_send_request(client, request, timeout) for request in requests] return await asyncio.gather(*send_requests) -async def _send_request(apns, request): +async def _send_request(apns, request, timeout): try: - res = await asyncio.wait_for(apns.send_notification(request), timeout=1) + res = await asyncio.wait_for(apns.send_notification(request), timeout=timeout) return request.device_token, res except asyncio.TimeoutError: return request.device_token, NotificationResult( diff --git a/push_notifications/conf/app.py b/push_notifications/conf/app.py index a70aa1f5..ab8d83af 100644 --- a/push_notifications/conf/app.py +++ b/push_notifications/conf/app.py @@ -51,7 +51,7 @@ APNS_AUTH_CREDS_OPTIONAL = ["CERTIFICATE", "ENCRYPTION_ALGORITHM", "TOKEN_LIFETIME"] APNS_OPTIONAL_SETTINGS = [ - "USE_SANDBOX", "USE_ALTERNATIVE_PORT", "TOPIC" + "USE_SANDBOX", "USE_ALTERNATIVE_PORT", "TOPIC", "ERROR_TIMEOUT" ] FCM_REQUIRED_SETTINGS = [] @@ -165,6 +165,7 @@ def _validate_apns_config(self, application_id, application_config): application_config.setdefault("USE_SANDBOX", False) application_config.setdefault("USE_ALTERNATIVE_PORT", False) application_config.setdefault("TOPIC", None) + application_config.setdefault("ERROR_TIMEOUT", 1) def _validate_apns_certificate(self, certfile): """Validate the APNS certificate at startup.""" @@ -335,6 +336,9 @@ def get_apns_use_alternative_port(self, application_id=None): def get_apns_topic(self, application_id=None): return self._get_application_settings(application_id, "APNS", "TOPIC") + def get_apns_error_timeout(self, application_id=None): + return self._get_application_settings(application_id, "APNS", "ERROR_TIMEOUT") + def get_wns_package_security_id(self, application_id=None): return self._get_application_settings(application_id, "WNS", "PACKAGE_SECURITY_ID") diff --git a/push_notifications/conf/legacy.py b/push_notifications/conf/legacy.py index 93a64cab..9dd14499 100644 --- a/push_notifications/conf/legacy.py +++ b/push_notifications/conf/legacy.py @@ -110,6 +110,9 @@ def get_apns_feedback_host(self, application_id=None): def get_apns_feedback_port(self, application_id=None): return self._get_application_settings(application_id, "APNS_FEEDBACK_PORT", self.msg) + def get_apns_error_timeout(self, application_id=None): + return self._get_application_settings(application_id, "APNS_ERROR_TIMEOUT") + def get_wns_package_security_id(self, application_id=None): return self._get_application_settings(application_id, "WNS_PACKAGE_SECURITY_ID", self.msg) diff --git a/push_notifications/settings.py b/push_notifications/settings.py index 5fba8b33..cbc270d3 100644 --- a/push_notifications/settings.py +++ b/push_notifications/settings.py @@ -18,6 +18,7 @@ PUSH_NOTIFICATIONS_SETTINGS.setdefault("APNS_USE_SANDBOX", False) PUSH_NOTIFICATIONS_SETTINGS.setdefault("APNS_USE_ALTERNATIVE_PORT", False) PUSH_NOTIFICATIONS_SETTINGS.setdefault("APNS_TOPIC", None) +PUSH_NOTIFICATIONS_SETTINGS.setdefault("APNS_ERROR_TIMEOUT", 1) # WNS PUSH_NOTIFICATIONS_SETTINGS.setdefault("WNS_PACKAGE_SECURITY_ID", None)