-
Notifications
You must be signed in to change notification settings - Fork 147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clarify use of 'FCM' in app type and refactor to use 'FCM' #251
Changes from 11 commits
5341baf
3add50f
e084e08
73654cd
cc0a87b
0370eaf
bcdb295
e068280
819c065
5751c57
58c5238
276e448
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1 @@ | ||||||
Addresses #230, refactors sygnal to use fcm as app type rather than gcm, and warns in documents about the deprecation of gcm as an app type. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -198,13 +198,16 @@ apps: | |||||||||||||||
# # The default is 'production'. Uncomment to use the sandbox instance. | ||||||||||||||||
# #platform: sandbox | ||||||||||||||||
|
||||||||||||||||
# This is an example GCM/FCM push configuration. | ||||||||||||||||
# This is an example FCM/GCM push configuration. Note that the gcm type is a legacy | ||||||||||||||||
# setting as we now use Firebase Cloud Messaging (fcm) exclusively. Setting gcm as the | ||||||||||||||||
# app type is still accepted but understand that under the hood we are using fcm. | ||||||||||||||||
# The gcm app type is deprecated. | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
# | ||||||||||||||||
#com.example.myapp.android: | ||||||||||||||||
# type: gcm | ||||||||||||||||
# api_key: your_api_key_for_gcm | ||||||||||||||||
# type: fcm or gcm | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
no point suggesting something that's deprecated, I'd say (also it should be directly uncommentable so that it works) |
||||||||||||||||
# api_key: your_api_key_for_fcm | ||||||||||||||||
# | ||||||||||||||||
# # This is the maximum number of connections to GCM servers at any one time | ||||||||||||||||
# # This is the maximum number of connections to FCM servers at any one time | ||||||||||||||||
# # the default is 20. | ||||||||||||||||
# #max_connections: 20 | ||||||||||||||||
# | ||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -37,38 +37,38 @@ | |||||||||||||
from .notifications import ConcurrencyLimitedPushkin | ||||||||||||||
|
||||||||||||||
QUEUE_TIME_HISTOGRAM = Histogram( | ||||||||||||||
"sygnal_gcm_queue_time", "Time taken waiting for a connection to GCM" | ||||||||||||||
"sygnal_fcm_queue_time", "Time taken waiting for a connection to FCM" | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
SEND_TIME_HISTOGRAM = Histogram( | ||||||||||||||
"sygnal_gcm_request_time", "Time taken to send HTTP request to GCM" | ||||||||||||||
"sygnal_fcm_request_time", "Time taken to send HTTP request to FCM" | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
PENDING_REQUESTS_GAUGE = Gauge( | ||||||||||||||
"sygnal_pending_gcm_requests", "Number of GCM requests waiting for a connection" | ||||||||||||||
"sygnal_pending_fcm_requests", "Number of FCM requests waiting for a connection" | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
ACTIVE_REQUESTS_GAUGE = Gauge( | ||||||||||||||
"sygnal_active_gcm_requests", "Number of GCM requests in flight" | ||||||||||||||
"sygnal_active_fcm_requests", "Number of FCM requests in flight" | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
RESPONSE_STATUS_CODES_COUNTER = Counter( | ||||||||||||||
"sygnal_gcm_status_codes", | ||||||||||||||
"Number of HTTP response status codes received from GCM", | ||||||||||||||
"sygnal_fcm_status_codes", | ||||||||||||||
"Number of HTTP response status codes received from FCM", | ||||||||||||||
labelnames=["pushkin", "code"], | ||||||||||||||
Comment on lines
-40
to
58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that modifying these will likely break existing metrics dashboards. Thus this (as well as the span tag name changes below) will need to be detailed in the changelog as well so sysadmins aren't caught off guard 🙂 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So afaict my main branch is up to date with the latest sygnal changes, and this fork as well-attempting to merge from main just gives an "Already up to date" message, yet the changelog check is still failing. I can't tell if I am missing something simple here! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like it's passing now! (Thanks @reivilibre!) |
||||||||||||||
) | ||||||||||||||
|
||||||||||||||
logger = logging.getLogger(__name__) | ||||||||||||||
|
||||||||||||||
GCM_URL = b"https://fcm.googleapis.com/fcm/send" | ||||||||||||||
FCM_URL = b"https://fcm.googleapis.com/fcm/send" | ||||||||||||||
MAX_TRIES = 3 | ||||||||||||||
RETRY_DELAY_BASE = 10 | ||||||||||||||
MAX_BYTES_PER_FIELD = 1024 | ||||||||||||||
|
||||||||||||||
# The error codes that mean a registration ID will never | ||||||||||||||
# succeed and we should reject it upstream. | ||||||||||||||
# We include NotRegistered here too for good measure, even | ||||||||||||||
# though gcm-client 'helpfully' extracts these into a separate | ||||||||||||||
# though fcm-client 'helpfully' extracts these into a separate | ||||||||||||||
# list. | ||||||||||||||
BAD_PUSHKEY_FAILURE_CODES = [ | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
However, gcm-client isn't even in use, so this comment is probably very crufty — hence I think it should just be removed altogether. |
||||||||||||||
"MissingRegistration", | ||||||||||||||
|
@@ -86,9 +86,9 @@ | |||||||||||||
DEFAULT_MAX_CONNECTIONS = 20 | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
class GcmPushkin(ConcurrencyLimitedPushkin): | ||||||||||||||
class FcmPushkin(ConcurrencyLimitedPushkin): | ||||||||||||||
""" | ||||||||||||||
Pushkin that relays notifications to Google/Firebase Cloud Messaging. | ||||||||||||||
Pushkin that relays notifications to Firebase Cloud Messaging. | ||||||||||||||
""" | ||||||||||||||
|
||||||||||||||
UNDERSTOOD_CONFIG_FIELDS = { | ||||||||||||||
|
@@ -99,7 +99,7 @@ class GcmPushkin(ConcurrencyLimitedPushkin): | |||||||||||||
} | ConcurrencyLimitedPushkin.UNDERSTOOD_CONFIG_FIELDS | ||||||||||||||
|
||||||||||||||
def __init__(self, name, sygnal, config): | ||||||||||||||
super(GcmPushkin, self).__init__(name, sygnal, config) | ||||||||||||||
super(FcmPushkin, self).__init__(name, sygnal, config) | ||||||||||||||
|
||||||||||||||
nonunderstood = set(self.cfg.keys()).difference(self.UNDERSTOOD_CONFIG_FIELDS) | ||||||||||||||
if len(nonunderstood) > 0: | ||||||||||||||
|
@@ -177,14 +177,14 @@ async def _perform_http_request(self, body, headers): | |||||||||||||
with ACTIVE_REQUESTS_GAUGE.track_inprogress(): | ||||||||||||||
response = await self.http_agent.request( | ||||||||||||||
b"POST", | ||||||||||||||
GCM_URL, | ||||||||||||||
FCM_URL, | ||||||||||||||
headers=Headers(headers), | ||||||||||||||
bodyProducer=body_producer, | ||||||||||||||
) | ||||||||||||||
response_text = (await readBody(response)).decode() | ||||||||||||||
except Exception as exception: | ||||||||||||||
raise TemporaryNotificationDispatchException( | ||||||||||||||
"GCM request failure" | ||||||||||||||
"FCM request failure" | ||||||||||||||
) from exception | ||||||||||||||
finally: | ||||||||||||||
self.connection_semaphore.release() | ||||||||||||||
|
@@ -201,7 +201,7 @@ async def _request_dispatch(self, n, log, body, headers, pushkeys, span): | |||||||||||||
pushkin=self.name, code=response.code | ||||||||||||||
).inc() | ||||||||||||||
|
||||||||||||||
log.debug("GCM request took %f seconds", time.time() - poke_start_time) | ||||||||||||||
log.debug("FCM request took %f seconds", time.time() - poke_start_time) | ||||||||||||||
|
||||||||||||||
span.set_tag(tags.HTTP_STATUS_CODE, response.code) | ||||||||||||||
|
||||||||||||||
|
@@ -217,7 +217,7 @@ async def _request_dispatch(self, n, log, body, headers, pushkeys, span): | |||||||||||||
span.log_kv({"event": "gcm_retry_after", "retry_after": retry_after}) | ||||||||||||||
|
||||||||||||||
raise TemporaryNotificationDispatchException( | ||||||||||||||
"GCM server error, hopefully temporary.", custom_retry_delay=retry_after | ||||||||||||||
"FCM server error, hopefully temporary.", custom_retry_delay=retry_after | ||||||||||||||
) | ||||||||||||||
elif response.code == 400: | ||||||||||||||
log.error( | ||||||||||||||
|
@@ -241,7 +241,7 @@ async def _request_dispatch(self, n, log, body, headers, pushkeys, span): | |||||||||||||
try: | ||||||||||||||
resp_object = json_decoder.decode(response_text) | ||||||||||||||
except ValueError: | ||||||||||||||
raise NotificationDispatchException("Invalid JSON response from GCM.") | ||||||||||||||
raise NotificationDispatchException("Invalid JSON response from FCM.") | ||||||||||||||
if "results" not in resp_object: | ||||||||||||||
log.error( | ||||||||||||||
"%d from server but response contained no 'results' key: %r", | ||||||||||||||
|
@@ -269,7 +269,7 @@ async def _request_dispatch(self, n, log, body, headers, pushkeys, span): | |||||||||||||
log.warning( | ||||||||||||||
"Error for pushkey %s: %s", pushkeys[i], result["error"] | ||||||||||||||
) | ||||||||||||||
span.set_tag("gcm_error", result["error"]) | ||||||||||||||
span.set_tag("fcm_error", result["error"]) | ||||||||||||||
if result["error"] in BAD_PUSHKEY_FAILURE_CODES: | ||||||||||||||
log.info( | ||||||||||||||
"Reg ID %r has permanently failed with code %r: " | ||||||||||||||
|
@@ -294,7 +294,7 @@ async def _request_dispatch(self, n, log, body, headers, pushkeys, span): | |||||||||||||
return failed, new_pushkeys | ||||||||||||||
else: | ||||||||||||||
raise NotificationDispatchException( | ||||||||||||||
f"Unknown GCM response code {response.code}" | ||||||||||||||
f"Unknown FCM response code {response.code}" | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
async def _dispatch_notification_unlimited(self, n, device, context): | ||||||||||||||
|
@@ -312,12 +312,12 @@ async def _dispatch_notification_unlimited(self, n, device, context): | |||||||||||||
# The pushkey is kind of secret because you can use it to send push | ||||||||||||||
# to someone. | ||||||||||||||
# span_tags = {"pushkeys": pushkeys} | ||||||||||||||
span_tags = {"gcm_num_devices": len(pushkeys)} | ||||||||||||||
span_tags = {"fcm_num_devices": len(pushkeys)} | ||||||||||||||
|
||||||||||||||
with self.sygnal.tracer.start_span( | ||||||||||||||
"gcm_dispatch", tags=span_tags, child_of=context.opentracing_span | ||||||||||||||
"fcm_dispatch", tags=span_tags, child_of=context.opentracing_span | ||||||||||||||
) as span_parent: | ||||||||||||||
data = GcmPushkin._build_data(n, device) | ||||||||||||||
data = FcmPushkin._build_data(n, device) | ||||||||||||||
headers = { | ||||||||||||||
b"User-Agent": ["sygnal"], | ||||||||||||||
b"Content-Type": ["application/json"], | ||||||||||||||
|
@@ -343,7 +343,7 @@ async def _dispatch_notification_unlimited(self, n, device, context): | |||||||||||||
span_tags = {"retry_num": retry_number} | ||||||||||||||
|
||||||||||||||
with self.sygnal.tracer.start_span( | ||||||||||||||
"gcm_dispatch_try", tags=span_tags, child_of=span_parent | ||||||||||||||
"fcm_dispatch_try", tags=span_tags, child_of=span_parent | ||||||||||||||
) as span: | ||||||||||||||
new_failed, new_pushkeys = await self._request_dispatch( | ||||||||||||||
n, log, body, headers, pushkeys, span | ||||||||||||||
|
@@ -375,7 +375,7 @@ async def _dispatch_notification_unlimited(self, n, device, context): | |||||||||||||
if len(pushkeys) > 0: | ||||||||||||||
log.info("Gave up retrying reg IDs: %r", pushkeys) | ||||||||||||||
# Count the number of failed devices. | ||||||||||||||
span_parent.set_tag("gcm_num_failed", len(failed)) | ||||||||||||||
span_parent.set_tag("fcm_num_failed", len(failed)) | ||||||||||||||
return failed | ||||||||||||||
|
||||||||||||||
@staticmethod | ||||||||||||||
|
@@ -409,7 +409,7 @@ def _build_data(n, device): | |||||||||||||
if hasattr(n, attr): | ||||||||||||||
data[attr] = getattr(n, attr) | ||||||||||||||
# Truncate fields to a sensible maximum length. If the whole | ||||||||||||||
# body is too long, GCM will reject it. | ||||||||||||||
# body is too long, FCM will reject it. | ||||||||||||||
if data[attr] is not None and len(data[attr]) > MAX_BYTES_PER_FIELD: | ||||||||||||||
data[attr] = data[attr][0:MAX_BYTES_PER_FIELD] | ||||||||||||||
|
||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.