Skip to content

Commit f93e8fb

Browse files
authored
Log at once user_ids of users suffering from senderId mismatch (#839)
### Context * Many logs all the time * They are useless (only tell a senderId which is deleted immediately after * Many users don't receive important notifs ### What this PR does * Distinguish the `UnregisteredError`, the `SenderIdMismatchError` and the rest * Log once for everyone who got a senderId mismatch * and log the useful pieces of info, i.e. `user_id` * Add missing types * `TODO:` retry immediately after for whom the notif failed (with a new token), or remember the list
1 parent 4a92a26 commit f93e8fb

File tree

2 files changed

+50
-7
lines changed

2 files changed

+50
-7
lines changed

app/core/notification/cruds_notification.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from sqlalchemy.ext.asyncio import AsyncSession
77

88
from app.core.notification import models_notification
9+
from app.core.users import models_users
910

1011

1112
async def get_notification_topic(
@@ -252,3 +253,18 @@ async def get_firebase_tokens_by_user_ids(
252253
),
253254
)
254255
return list(result.scalars().all())
256+
257+
258+
async def get_usernames_by_firebase_tokens(
259+
tokens: list[str],
260+
db: AsyncSession,
261+
) -> list[str]:
262+
result = await db.execute(
263+
select(models_users.CoreUser)
264+
.join(
265+
models_notification.FirebaseDevice,
266+
models_users.CoreUser.id == models_notification.FirebaseDevice.user_id,
267+
)
268+
.where(models_notification.FirebaseDevice.firebase_device_token.in_(tokens)),
269+
)
270+
return [f"{u.firstname} {u.name}" for u in list(result.scalars().all())]

app/utils/communication/notifications.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def __init__(self, settings: Settings):
4242

4343
async def _manage_firebase_batch_response(
4444
self,
45+
message_content: Message,
4546
response: messaging.BatchResponse,
4647
tokens: list[str],
4748
db: AsyncSession,
@@ -50,22 +51,47 @@ async def _manage_firebase_batch_response(
5051
Manage the response of a firebase notification. We need to assume that tokens that failed to be send are not valid anymore and delete them from the database.
5152
"""
5253
if response.failure_count > 0:
53-
responses = response.responses
54-
failed_tokens = []
54+
responses: list[messaging.SendResponse] = response.responses
55+
failed_tokens: list[str] = []
56+
mismatching_tokens: list[str] = []
5557
for idx, resp in enumerate(responses):
5658
if not resp.success:
5759
# Firebase may return different errors: https://firebase.google.com/docs/reference/admin/python/firebase_admin.messaging#exceptions
5860
# UnregisteredError happens when the token is not valid anymore, and should thus be removed from the database
59-
# Other errors may happen, we want to log them as they may indicate a problem with the firebase configuration
61+
# Other errors may happen, we want to log them as they may indicate a problem with the firebase configuration.
62+
# We cannot do more from the back-end to have the user eventually receive the notification.
6063
if not isinstance(
6164
resp.exception,
62-
firebase_admin.messaging.UnregisteredError,
65+
messaging.UnregisteredError,
6366
):
64-
hyperion_error_logger.error(
65-
f"Firebase: Failed to send firebase notification to token {tokens[idx]}: {resp.exception}",
66-
)
67+
if isinstance(
68+
resp.exception,
69+
messaging.SenderIdMismatchError,
70+
):
71+
mismatching_tokens.append(tokens[idx])
72+
else:
73+
hyperion_error_logger.error(
74+
f"Firebase: Failed to send firebase notification to token {tokens[idx]}: {resp.exception}",
75+
)
6776
# The order of responses corresponds to the order of the registration tokens.
6877
failed_tokens.append(tokens[idx])
78+
if len(mismatching_tokens) > 0:
79+
usernames = await cruds_notification.get_usernames_by_firebase_tokens(
80+
tokens=mismatching_tokens,
81+
db=db,
82+
)
83+
hyperion_error_logger.error(
84+
"""
85+
Firebase: SenderId mismatch for notification '%s' (%s module) for %s/%s tokens (%s users) :
86+
%s
87+
""",
88+
message_content.title,
89+
message_content.action_module,
90+
len(mismatching_tokens),
91+
response.success_count + response.failure_count,
92+
len(usernames),
93+
"\n".join(usernames),
94+
)
6995
hyperion_error_logger.info(
7096
f"{response.failure_count} messages failed to be send, removing their tokens from the database.",
7197
)
@@ -121,6 +147,7 @@ async def _send_firebase_push_notification_by_tokens(
121147
)
122148
raise
123149
await self._manage_firebase_batch_response(
150+
message_content,
124151
response=result,
125152
tokens=tokens,
126153
db=db,

0 commit comments

Comments
 (0)