Exact File Paths
backend/controllers/cronController.js (Lines 112 - 130)
The Core Problem
The dispatchPushNotifications cron job maps over all database subscriptions to send push notifications via Promise.allSettled. However, when a browser revokes permission or a subscription expires, web-push rejects the promise with a 410 Gone or 404 status code. The current implementation catches these failures but never deletes the dead endpoints from the database.
The Reproducible Scenario / Impact
Over time, the push_subscriptions table will fill up with dead endpoints as users switch devices or revoke permissions. Because the cron job runs continuously, it will waste network bandwidth, CPU time, and database resources attempting to execute VAPID handshakes with endpoints that no longer exist, eventually causing the cron job to timeout or hit database connection limits.
Step-by-Step Suggested Solution
- After
await Promise.allSettled(...), iterate through pushResults.
- Filter for rejected promises where
result.reason.statusCode === 410 || result.reason.statusCode === 404.
- Map these to their original
subscription.endpoint.
- Run a bulk Supabase deletion:
await supabase.from("push_subscriptions").delete().in("endpoint", deadEndpoints);.
Exact File Paths
backend/controllers/cronController.js(Lines 112 - 130)The Core Problem
The
dispatchPushNotificationscron job maps over all database subscriptions to send push notifications viaPromise.allSettled. However, when a browser revokes permission or a subscription expires,web-pushrejects the promise with a410 Goneor404status code. The current implementation catches these failures but never deletes the dead endpoints from the database.The Reproducible Scenario / Impact
Over time, the
push_subscriptionstable will fill up with dead endpoints as users switch devices or revoke permissions. Because the cron job runs continuously, it will waste network bandwidth, CPU time, and database resources attempting to execute VAPID handshakes with endpoints that no longer exist, eventually causing the cron job to timeout or hit database connection limits.Step-by-Step Suggested Solution
await Promise.allSettled(...), iterate throughpushResults.result.reason.statusCode === 410 || result.reason.statusCode === 404.subscription.endpoint.await supabase.from("push_subscriptions").delete().in("endpoint", deadEndpoints);.