push_notifications: Lazily import APNS libraries.

The APNS client libraries (especially the hyper.http20 one) were
determined via profiling to take significant time during the import
process, so we move them to be lazily imported in order to optimize
the overall Zulip import process.  This save up to about 100ms in
import time.

These libraries are only used in certain Django processes inside
zulipchat.com, and so are unnecessary both in development as well as
for self-hosted Zulip servers.
This commit is contained in:
Tim Abbott
2018-08-08 09:16:57 -07:00
parent ec9f6702d8
commit 2eebacf2dc
2 changed files with 15 additions and 7 deletions

View File

@@ -12,14 +12,11 @@ import random
from typing import Any, Dict, List, Optional, SupportsInt, Tuple, Type, Union
from apns2.client import APNsClient
from apns2.payload import Payload as APNsPayload
from django.conf import settings
from django.db import IntegrityError, transaction
from django.utils.timezone import now as timezone_now
from django.utils.translation import ugettext as _
from gcm import GCM
from hyper.http20.exceptions import HTTP20Error
import requests
import urllib
import ujson
@@ -55,10 +52,13 @@ def hex_to_b64(data: str) -> bytes:
# Sending to APNs, for iOS
#
_apns_client = None # type: Optional[APNsClient]
_apns_client = None # type: Optional[Any]
_apns_client_initialized = False
def get_apns_client() -> APNsClient:
def get_apns_client() -> Any:
# We lazily do this import as part of optimizing Zulip's base
# import time.
from apns2.client import APNsClient
global _apns_client, _apns_client_initialized
if not _apns_client_initialized:
# NB if called concurrently, this will make excess connections.
@@ -104,7 +104,15 @@ APNS_MAX_RETRIES = 3
@statsd_increment("apple_push_notification")
def send_apple_push_notification(user_id: int, devices: List[DeviceToken],
payload_data: Dict[str, Any], remote: bool=False) -> None:
client = get_apns_client()
# We lazily do the APNS imports as part of optimizing Zulip's base
# import time; since these are only needed in the push
# notification queue worker, it's best to only import them in the
# code that needs them.
from apns2.payload import Payload as APNsPayload
from apns2.client import APNsClient
from hyper.http20.exceptions import HTTP20Error
client = get_apns_client() # type: APNsClient
if client is None:
logging.warning("APNs: Dropping a notification because nothing configured. "
"Set PUSH_NOTIFICATION_BOUNCER_URL (or APNS_CERT_FILE).")