Skip to content

Commit 792dbc8

Browse files
committed
feat(push_notifications): add cleanup
1 parent a7ae884 commit 792dbc8

File tree

1 file changed

+63
-4
lines changed

1 file changed

+63
-4
lines changed

lib/src/services/push_notification_service.dart

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,24 @@ class DefaultPushNotificationService implements IPushNotificationService {
222222

223223
if (userDeviceTokens.isNotEmpty) {
224224
// Add the send operation to the list of futures.
225+
// The result of this future will contain information about which
226+
// tokens succeeded and which failed.
225227
sendFutures.add(
226-
client.sendBulkNotifications(
227-
deviceTokens: userDeviceTokens,
228-
payload: notification.payload,
229-
),
228+
client
229+
.sendBulkNotifications(
230+
deviceTokens: userDeviceTokens,
231+
payload: notification.payload,
232+
)
233+
.then((result) {
234+
// After the send completes, trigger the cleanup process for
235+
// any failed tokens. This is a fire-and-forget operation.
236+
unawaited(
237+
_cleanupInvalidDevices(
238+
result.failedTokens,
239+
primaryProvider,
240+
),
241+
);
242+
}),
230243
);
231244
}
232245
} catch (e, s) {
@@ -255,4 +268,50 @@ class DefaultPushNotificationService implements IPushNotificationService {
255268
);
256269
}
257270
}
271+
272+
/// Deletes device registrations associated with a list of invalid tokens.
273+
///
274+
/// This method is called after a push notification send operation to prune
275+
/// the database of tokens that the provider has identified as unregistered
276+
/// or invalid (e.g., because the app was uninstalled).
277+
///
278+
/// - [invalidTokens]: A list of device tokens that failed to be delivered.
279+
/// - [provider]: The push notification provider that reported the tokens as
280+
/// invalid.
281+
Future<void> _cleanupInvalidDevices(
282+
List<String> invalidTokens,
283+
PushNotificationProvider provider,
284+
) async {
285+
if (invalidTokens.isEmpty) {
286+
return; // Nothing to clean up.
287+
}
288+
289+
_log.info(
290+
'Cleaning up ${invalidTokens.length} invalid device tokens for provider "$provider".',
291+
);
292+
293+
// Retrieve the list of devices that match the filter criteria.
294+
final devicesToDelete = await _pushNotificationDeviceRepository.readAll(
295+
filter: {
296+
'providerTokens.${provider.name}': {r'$in': invalidTokens},
297+
},
298+
);
299+
300+
try {
301+
// Delete the devices one by one.
302+
// While this is less efficient than a bulk delete, it is necessary
303+
// as `DataRepository` does not have a `deleteAll` method.
304+
await Future.forEach<PushNotificationDevice>(devicesToDelete.items, (
305+
device,
306+
) async {
307+
await _pushNotificationDeviceRepository.delete(id: device.id);
308+
});
309+
310+
_log.info('Successfully cleaned up invalid device tokens.');
311+
} catch (e, s) {
312+
_log.severe('Failed to clean up invalid device tokens.', e, s);
313+
// We log the error but do not rethrow, as this is a background
314+
// cleanup task and should not crash the main application flow.
315+
}
316+
}
258317
}

0 commit comments

Comments
 (0)