Skip to content
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

Push Notifications setting lost again #411

Open
SatsAllDay opened this issue Aug 15, 2023 · 38 comments
Open

Push Notifications setting lost again #411

SatsAllDay opened this issue Aug 15, 2023 · 38 comments

Comments

@SatsAllDay
Copy link
Contributor

SatsAllDay commented Aug 15, 2023

Description
It appears I have again lost the setting where I enabled push notifications. I think this was an issue in the past that was fixed at one point.

Steps to Reproduce
Open PWA and find Push Notifications disabled on the notifications page when it was enabled previously.

Expected behavior
Push notifications remains enabled if enabled.

Screenshots
N/A

Logs
N/A

Environment:
iOS PWA

Additional context
N/A

cc @ekzyis

@ekzyis ekzyis added the bug label Aug 15, 2023
@ekzyis
Copy link
Member

ekzyis commented Aug 15, 2023

Are you sure this was fixed at one point? I think it just happens randomly.

And seems like the latest changes didn't work. It should resubscribe you automatically if your push subscription expired and you were subscribed before.

@SatsAllDay
Copy link
Contributor Author

No, I am not sure it was fixed. I thought it was reported as fixed, but perhaps that was just optimistic :)

Let me know if there's any additional information I can provide to help debug further.

@ekzyis
Copy link
Member

ekzyis commented Aug 15, 2023

No, I am not sure it was fixed. I thought it was reported as fixed, but perhaps that was just optimistic :)

Ah, I see, haha, yes, we were hoping in this release it would be fixed now with these changes.

Let me know if there's any additional information I can provide to help debug further.

Thanks for the offer, now that you ask, there might indeed be something: Can you confirm if anything is saved as subscription in your IndexedDB? Don't share the full URL / the keys of the subscription since anyone could use that to send push subscriptions to your device. If anything is stored there, it should be the current subscription and thus fine.

2023-08-15-164527_598x281_scrot

Other than that, I don't think there is any more information we can request at the moment. I also just noticed we don't log user ids during web push errors so we can't associate errors with users with specific subscriptions at the moment. Will push a fix soon.

Opt-in client-side logging would be useful at this point for debugging now. I have only worked with Sentry so far and Sentry seems overkill for us at this stage. This website mentions some simpler alternatives including just rolling our own code.

@huumn, what do you think about client-side logging?

@huumn
Copy link
Member

huumn commented Aug 15, 2023

I'm for it. Two requirements:

  1. without a doubt doesn't violate user privacy
  2. without a doubt helps us help stackers

@SatsAllDay
Copy link
Contributor Author

Thanks for the offer, now that you ask, there might indeed be something: Can you confirm if anything is saved as subscription in your IndexedDB? Don't share the full URL / the keys of the subscription since anyone could use that to send push subscriptions to your device. If anything is stored there, it should be the current subscription and thus fine.

On my desktop, yes. I don't know how to check this on my iOS device though, which is where I noticed the problem.

@ekzyis ekzyis self-assigned this Aug 16, 2023
@huumn
Copy link
Member

huumn commented Aug 28, 2023

Can confirm this isn't fixed on iOS at least

@SatsAllDay
Copy link
Contributor Author

Same, my setting gets lost every few days it seems.

@ekzyis
Copy link
Member

ekzyis commented Sep 20, 2023

#463 worked and I think we found the culprit thanks to a HN post:

7-Day Cap on All Script-Writeable Storage

-- https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/

So this means your Apple devices delete the existing subscription in IndexedDB and then, when the service worker checks if the subscription needs an update, it does not find a previous one. Therefore, it does not send the updated subscription to our server:

sw/index.js

async function handlePushSubscriptionChange (oldSubscription, newSubscription) {
  // https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/pushsubscriptionchange_event
  // fallbacks since browser may not set oldSubscription and newSubscription
  oldSubscription ??= await storage.getItem('subscription')
  newSubscription ??= await self.registration.pushManager.getSubscription()
  if (!newSubscription) {
    // no subscription exists at the moment
    return
  }
  if (oldSubscription?.endpoint === newSubscription.endpoint) {
    // subscription did not change. no need to sync with server
    return
  }

This updated subscription is also not stored in IndexedDB then since that only happens if you click the button or an updated subscription was sent to the server.

What happens then is my assumption: At this point, there is still an active subscription on your device (so the checkbox in /notifications is still checked) but the server cannot send you any events anymore (since it doesn't have the updated subscription). I think this subscription expires at some point without an update since it was never used by the server.

Then your checkbox is also unchecked.

ladies-and-gentleman-we-got-him

I haven't fully confirmed this since there might have been some changes (the article is from 2020) but I think this is it.

@ekzyis
Copy link
Member

ekzyis commented Sep 20, 2023

Mhh, but reading the resource thoroughly:

deleting all of a website’s script-writable storage after seven days of Safari use without user interaction on the site

What counts as a "user interaction"? Anything? Then IndexedDB should not have been cleared.

A Note On Web Applications Added to the Home Screen
As mentioned, the seven-day cap on script-writable storage is gated on “after seven days of Safari use without user interaction on the site.” That is the case in Safari. Web applications added to the home screen are not part of Safari and thus have their own counter of days of use. Their days of use will match actual use of the web application which resets the timer. We do not expect the first-party in such a web application to have its website data deleted.

If your web application does experience website data deletion, please let us know since we would consider it a serious bug. It is not the intention of Intelligent Tracking Prevention to delete website data for first parties in web applications.

Web apps added to home screen = PWAs? Also, actual use resets the timer? The timer does not seem to have been reset here.

So either:

  1. this is a bug
  2. this behavior changed and it gets deleted even with user interaction
  3. i don't really understand this text

edit: 4) or of course, this is not the real reason

For sake of completeness, here the related log lines:

2023-09-19T04:02:13.342Z |  51 [info] ███ | sent SYNC_SUBSCRIPTION to service worker | - | os=iOS
2023-09-19T04:02:13.463Z |  54 [info] ███ | [sw:handlePushSubscriptionChange] old subscription matches existing subscription | - | os=iOS
2023-09-19T15:08:32.235Z | 205 [info] ███ | sent SYNC_SUBSCRIPTION to service worker | - | os=iOS
2023-09-19T15:08:32.321Z | 208 [info] ███ | [sw:handlePushSubscriptionChange] no existing subscription found | - | os=iOS
2023-09-20T04:24:48.269Z | 441 [info] ███ | subscribed to push notifications | endpoint=███ | os=iOS

log 51 and 54 show that there was still a push subscription.
log 205 and 208 then show there is suddenly no push subscription anymore ... but wait.

I just checked the code and this line is printed if the service worker has no active subscription anymore:

  newSubscription ??= await self.registration.pushManager.getSubscription()
  if (!newSubscription) {
    // no subscription exists at the moment
    messageChannelPort?.postMessage({ message: '[sw:handlePushSubscriptionChange] no existing subscription found' })
    return
  }

So "existing" does not mean there is no subscription stored in IndexedDB at the moment. It means the service worker itself has no push subscription (=> checkbox unchecked). Therefore, the issue is because the service worker just lost the push subscription. However, the resource also mentions that registrations are deleted:

  • Service Worker registrations and cache

So this may still be the reason, I just missed that detail that it's not IndexedDB that we see to be suddenly empty, it's the actual registration of the service worker. And with that, push subscriptions are probably also gone.

@huumn
Copy link
Member

huumn commented Sep 20, 2023

This might be a red herring but it looks like we initially think service workers aren't supported, then we register one.

2023-09-20T12:42:05.725Z | 747 [info] serene-voyager-4004 | device does not support service worker | - | os=iOS
2023-09-20T12:42:05.818Z | 748 [info] serene-voyager-4004 | sent SYNC_SUBSCRIPTION to service worker | - | os=iOS
2023-09-20T12:42:05.864Z | 749 [info] serene-voyager-4004 | [sw:handlePushSubscriptionChange] old subscription matches existing subscription | - | os=iOS
2023-09-20T12:42:05.866Z | 750 [info] serene-voyager-4004 | [sw:message] received message | action=MESSAGE_PORT | os=iOS
2023-09-20T12:42:06.034Z | 752 [info] serene-voyager-4004 | service worker registration successful | - | os=iOS

@ekzyis
Copy link
Member

ekzyis commented Sep 20, 2023

Yes, it looks weird in the logs but this happens for every device. IIRC this is because of render order / useEffect. It first logs no support, then in the next render, the state is updated and the service worker is registered - something like that.

@huumn
Copy link
Member

huumn commented Oct 7, 2023

I've created a 500k bounty for this: https://stacker.news/items/277155

Also, we've learned this isn't strictly iOS. It also affects android devices

@SatsAllDay
Copy link
Contributor Author

A push subscription is a message delivery context established between the user agent and the push service on behalf of a web application. Each push subscription is associated with a service worker registration and a service worker registration has at most one push subscription. 1

This makes me wonder if we are replacing service worker registrations and that is causing the existing PushSubscription to be cleared?

I verified that the subscription is still stored in IndexedDB, but this line indicates that there is no PushSubscription found.

I also tried re-subscribing and verified that there is no expiration time set on the subscription, so that eliminates expiration as the source of this issue.

I don't know enough about service workers, but these lines feel like we're replacing the service worker registration, which could lead to removal of the push subscription, though if that was the case, I'd expect this to be a more persistent issue.

Footnotes

  1. https://w3c.github.io/push-api/#push-subscription

@ekzyis
Copy link
Member

ekzyis commented Nov 2, 2023

though if that was the case, I'd expect this to be a more persistent issue.

Yes, that's also what I would except. This means it should happen on every deployment which doesn't seem to be the case.

Unfortunately, it's hard for me to investigate this properly since I do not have this issue even though there was also someone on Android experiencing this issue.

However, I have an idea for a possible workaround (without really fixing the underlying issue since we don't know what is causing this):

We could delete the push subscription in IndexedDB if the user manually unchecks the push subscription.

In that case, we know that if the service worker has no push subscription but there is a push subscription in IndexedDB during SYNC_SUBSCRIPTION, this is probably the bug and we can register a new push subscription in the background and send that one to the server. Currently, we aren't able to distinguish between the bug and manually unsubscribing since in both cases, there would still be a push subscription in IndexedDB.

So this means that during unsubscribeFromPushNotifications, we would add code that also deletes the push subscription in IndexedDB:

const unsubscribeFromPushNotifications = async (subscription) => {
await subscription.unsubscribe()
const { endpoint } = subscription
logger.info('unsubscribed from push notifications', { endpoint })
await deletePushSubscription({ variables: { endpoint } })
logger.info('deleted push subscription from server', { endpoint })
}

And then, during SYNC_SUBSCRIPTION, if the service worker has no push subscription but there is one in IndexedDB, we assume it's a bug and automatically resubscribe:

navigator?.serviceWorker?.controller?.postMessage?.({ action: 'SYNC_SUBSCRIPTION' })

if (!newSubscription) {
// no subscription exists at the moment
messageChannelPort?.postMessage({ message: '[sw:handlePushSubscriptionChange] no existing subscription found' })
return
}
if (oldSubscription?.endpoint === newSubscription.endpoint) {
// subscription did not change. no need to sync with server
messageChannelPort?.postMessage({ message: '[sw:handlePushSubscriptionChange] old subscription matches existing subscription' })
return
}

@ekzyis
Copy link
Member

ekzyis commented Nov 2, 2023

I just realized that I've been using the wrong function signature for pushsubscriptionchange:

self.addEventListener('pushsubscriptionchange', onPushSubscriptionChange(self), false)

export function onPushSubscriptionChange (sw) {
// https://medium.com/@madridserginho/how-to-handle-webpush-api-pushsubscriptionchange-event-in-modern-browsers-6e47840d756f
return async (oldSubscription, newSubscription) => {

But I think that's unrelated to this bug since most browsers don't support this event anyway and it's the right function signature for the workaround code:

if (event.data.action === 'SYNC_SUBSCRIPTION') {
return event.waitUntil(onPushSubscriptionChange(sw)(event.oldSubscription, event.newSubscription))
}

@SatsAllDay
Copy link
Contributor Author

this is probably the bug and we can register a new push subscription in the background and send that one to the server.

My only concern is if this is "OK" to do since it wouldn't be driven by an explicit user interaction? To register a new push subscription automatically under certain conditions. Just food for thought. I like the workaround in general, should improve the experience!

@ekzyis
Copy link
Member

ekzyis commented Nov 3, 2023

My only concern is if this is "OK" to do since it wouldn't be driven by an explicit user interaction? To register a new push subscription automatically under certain conditions. Just food for thought. I like the workaround in general, should improve the experience!

Good point but I think it's okay since this only works if permissions were already granted. We're acting in the interest of our users here since they told us they want push notifications.

The user can always opt-out via browser settings. The "game theory" of permissions is that applications should behave with the permissions they were granted else the user will remove permission via the browser which is a "nuclear option" since the application won't even be able to ask for permission again then:

Your site should explain to your users how they can disable push. If you don't, users are likely to take the nuclear option and block permission permanently.

-- https://web.dev/articles/push-notifications-permissions-ux#the_bad_ux

@huumn
Copy link
Member

huumn commented Nov 15, 2023

Just lost mine again today ... after what felt like longer than normal at least!

@ekzyis
Copy link
Member

ekzyis commented Nov 15, 2023

Mhh, I think this was the related log message:

2023-11-14T23:46:33.717Z | 53568 [info] serene-voyager-4004 | [sw:handlePushSubscriptionChange] no existing subscription found | - | os=iOS

Since it says no existing subscription found instead of service worker lost subscription as in this line I think your old subscription in IndexedDB wasn't created with swVersion: 2 set yet

Maybe the resubscribe code will work now for you

@huumn
Copy link
Member

huumn commented Nov 15, 2023

Okay cool, will keep commenting here when they're lost

@ekzyis
Copy link
Member

ekzyis commented Dec 8, 2023

lol, it seems it's getting worse since it seems I am also starting to lose my push subscription now, lol

At least the checkbox is unchecked sometimes ...

Okay cool, will keep commenting here when they're lost

btw, can you also comment if you ever receive a random "Stacker News notifications are active now"? :)

@huumn
Copy link
Member

huumn commented Dec 8, 2023

I lose my notifications daily now and receive the "Stacker News notifications are active now" nearly every time I open the app, and it's a coinflip if my checkbox is checked. It's super super broken.

I suspect we're misunderstanding something about how these work on phones.

@ekzyis
Copy link
Member

ekzyis commented Dec 8, 2023

I lose my notifications daily now

What does "daily now" mean? How many days already?

and receive the "Stacker News notifications are active now" nearly every time I open the app, and it's a coinflip if my checkbox is checked. It's super super broken.

Yeah I wonder if I just never noticed that my checkbox might be unchecked ... i haven't tested if I might still receive push notifications even if it "seems" unchecked

But weird, I think we haven't changed anything in the service worker for a while?

$ git log -5 --oneline -- sw/*
0b872cb Only resubscribe on compatible old subscriptions (#616)
522c821 Notification badges (#595)
5dfeb70 Resubscribe if service worker lost push subscription (#597)
7040dbf Fix missing merge of FOLLOW push notifications (#596)
eeaf2d5 Fix FORWARDEDTIP change lost in serviceworker (#582)

0b872cb is from Nov 9

I suspect we're misunderstanding something about how these work on phones.

I suspect the only way we will be able to ever know what is going wrong is to get really serious with logging.

According to this, it's not really magic how this stuff is supposed to work:

The three key steps to implementing push are:

  1. Adding the client side logic to subscribe a user to push (i.e. the JavaScript and UI in your web app that registers a user to push messages).
  2. The API call from your back-end / application that triggers a push message to a user's device.
  3. The service worker JavaScript file that will receive a "push event" when the push arrives on the device. It's in this JavaScript that you'll be able to show a notification.

But I might just have to read the RFC in full, anyway. Maybe there is some useful information in there.

Or is the site we're building hitting some weird edge cases in the spec? Too many push notifications getting sent without some weird dance for the push service? Is our use case not the average use case for push notifications?

Speculations, speculations, lol

Another hope of mine is that if I implement push notifications for https://delphi.market/ (which uses Vue and Golang), I could use this implementation to send regular test push notifications to try to reproduce our issue on SN.

If it's not reproduce-able there ... bad luck, but still some valuable information, I guess.

@huumn
Copy link
Member

huumn commented Dec 8, 2023

It's been broken for awhile not just recently.

@huumn
Copy link
Member

huumn commented Dec 19, 2023

I wonder if this might be related to storage getting cleared when a device is running out of space. I have an old iphone that's constantly evicting apps and is probably also evicting pwa storage.

Perhaps we could use persistent storage? https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persist

@ekzyis
Copy link
Member

ekzyis commented Dec 19, 2023

I wonder if this might be related to storage getting cleared when a device is running out of space.

Ohh, my phone is also constantly running out of space. This might be indeed the reason that I also started to lose my push subscription recently.

Perhaps we could use persistent storage? https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persist

Sounds like a good idea!

Btw, this never happened on desktop, right? (or actually, not sure, it might have happened on desktop for me, too) 🤔

@huumn
Copy link
Member

huumn commented Dec 19, 2023

I don't have them enabled on desktop. I always have a tab open

@ekzyis
Copy link
Member

ekzyis commented Dec 20, 2023

👀

You can ask the browser for persistent storage on compatible platforms to avoid automatic data eviction after inactivity or on storage pressure. If granted, the browser will never evict data from storage. This protection includes the service worker registration, IndexedDB databases, and files in cache storage. Note that users are always in charge, and they can delete the storage at any time, even if the browser has granted persistent storage.

-- https://web.dev/learn/pwa/offline-data#data_persistence

Will create PR soon. If I understand this right, it's really just one simple API call.

Btw, just checked my quota in my brave desktop session (just out of interest):

> const s = await navigator.storage.estimate()
> s
{
    "quota": 2147483648,
    "usage": 200328181,
    "usageDetails": {
        "caches": 200018261,
        "indexedDB": 267159,
        "serviceWorkerRegistrations": 42761
    }
}
> s.usage / s.quota
0.09328507864847779

@huumn
Copy link
Member

huumn commented Dec 28, 2023

Are we maybe accidentally doing silent pushes? https://dev.to/progressier/how-to-fix-ios-push-subscriptions-being-terminated-after-3-notifications-39a7

We're using event.waitUntil in onPush but we aren't awaiting all the showNotification calls, ie we're returning a promise that returns a promise in several instances.

@ekzyis
Copy link
Member

ekzyis commented Dec 28, 2023

Are we maybe accidentally doing silent pushes? https://dev.to/progressier/how-to-fix-ios-push-subscriptions-being-terminated-after-3-notifications-39a7

We're using event.waitUntil in onPush but we aren't awaiting all the showNotification calls, ie we're returning a promise that returns a promise in several instances.

I think returning a promise inside a promise is fine. As far as my JS knowledge goes, there is no difference for the calling context if you do return <Promise> or return await <Promise> except if it's wrapped inside try/catch. Then you need to use await to trigger catch on errors. And afaict, we're always at least returning them. There are no "loose promises" when it comes to showNotification.

But we might be doing silent pushes elsewhere. I vaguely remember that I was wondering if X could cause a silent push but I no longer know what X was 🤔

update: Yeah, skipNotification causes silent pushes. I added them in this PR to fix #557. Guess we need to use server side logic as @SatsAllDay was going for.

Cool... I was going to fix this in the item resolver by doing a diff on the old vs new mentions, and conditionally sending pushes based on that. I wouldn't have thought of this approach. Nice!

-- #563 (comment)

I even mentioned that this could cause silent pushes but again, I didn't consider vastly different or even completely breaking behavior on iOS:

Potentially major issue: Silent push notifications may result in a default push notification:

With push events, there is an additional requirement that you must display a notification before the promise you passed in has settled.

-- https://web.dev/articles/push-notifications-handling-messages

(also some other sources I can't find anymore where I read more about this behavior)

I haven't witnessed this on Brave on Linux Desktop but I will check on Chrome Desktop and my Android phone (Chrome + Brave). Can someone check macOS and iOS?

If any device shows default push notifications (and we can't avoid it), we need to drop this approach and need to do something server side.

-- #563 (comment)

Good catch! I think this is definitely an issue.

@huumn
Copy link
Member

huumn commented Dec 28, 2023

I think returning a promise inside a promise is fine.

I don't think it is. What happens here afaict is by returning a promise the async function resolves to a potentially unresolved showNotification promise. Meaning, waitUntil is not waiting until showNotification resolves and the notification is not shown by the end of the event deterministically and these pushes are sometimes silent depending on how fast showNotification resolves.

@ekzyis
Copy link
Member

ekzyis commented Dec 28, 2023

I think returning a promise inside a promise is fine.

I don't think it is. What happens here afaict is by returning a promise the async function resolves to a potentially unresolved showNotification promise. Meaning, waitUntil is not waiting until showNotification resolves and the notification is not shown by the end of the event deterministically and these pushes are sometimes silent depending on how fast showNotification resolves.

Mhh, I see. I also see how my argument might have been too hand-wavy. I'll create a PR with return await on all these promises in a few minutes.

I'll also think about skipNotification more.

@huumn
Copy link
Member

huumn commented Dec 28, 2023

Basically this function can only return a promise if that promise resolves, and only resolves, if showNotification resolves.

@ekzyis
Copy link
Member

ekzyis commented Dec 29, 2023

For bookkeeping purposes, I'll write down here what we've just seen in our logs and discussed internally on Slack:

We've noticed that this if block gets triggered in iOS:

// fetch existing notifications with same tag
const notifications = await sw.registration.getNotifications({ tag })
// since we used a tag filter, there should only be zero or one notification
if (notifications.length > 1) {
  const message = `[sw:push] more than one notification with tag ${tag} found`
  messageChannelPort?.postMessage({ level: 'error', message })
  console.error(message)
  return null
}

because we've found a lot of

2023-12-29T04:25:28.208Z | 170071 [error] serene-voyager-4004 | [sw:push] more than one notification with tag REPLY found | - | os=iOS

in our logs.

This makes sense since when we released push notifications, we realized pretty quick that tag is not properly supported by Safari on iOS. I created a WebKit bug report because of this back in July.

This is another silent push because of which Safari might cancel push subscriptions.

However, reading the last response from someone working at Apple or WebKit (?) got me confused:

An additional data point: this appears to be partially working on macOS Safari. While a second notification with the same tag appears as a new entry in the system notification center, it does replace an existing one in the array returned by ServiceWorkerRegistration.getNotifications(), and a notificationclose event is fired for the old/replaced notification. (For comparison, macOS Chrome replaces the notification in both places, and does not fire a notificationclose event for the replaced notification.)

On iOS Safari, ServiceWorkerRegistration.getNotifications() appears to always return an empty array, so there's no way to compare that behaviour.

Afaict, this doesn't add up with what we're seeing on iOS. According to the log message, getNotifications({ tag }) does return an array with more than one element.

tl;dr: Next attempt to fix this issue: Create PR which does not rely on tag anymore in showNotification. And I'll call getNotifications({ tag }) but manually make sure that the array indeed only contains notifications with the same tag. As mentioned in the bug report, the tag property is correctly set on the notifications themselves:

To be clear: the tag attribute on Notification is exposed. You can set it via the Notification constructor/ServiceWorkerRegistration.showNotification and access its value later on. But the browser currently doesn't use the property to coalesce notifications. That will require additional work.

@ekzyis
Copy link
Member

ekzyis commented Jan 1, 2024

Regarding UX on Android since #719: It still works but I can definitely tell that it no longer uses the native tag property. The notifications appear but no longer smoothly replace each other. Especially on desktop, I can see how the notification is closed and then a new notification pops up since there are enough milliseconds between these two calls that it's noticeable.

So I think it makes sense to only run the code which does not depend on tag on iOS devices. This means we would need to detect the OS in the service worker, too. We currently only do that in the logger.

@huumn
Copy link
Member

huumn commented Jan 1, 2024

Agreed. We don't want to degrade android UX because iOS is behind.

Also, I've maintained my notifications longer than usual but I did lose them once yesterday. It might've just been a fluke.

I also spent sometime looking around for any clues about potential causes. It looks like many other devs have the same issue: https://developer.apple.com/forums/thread/728796

@ekzyis
Copy link
Member

ekzyis commented Jan 9, 2024

I have access to an iPhone with Safari on iOS 17.1 now. I was able to gather some information about what works and doesn't work.

The columns of the log messages are:

  1. log id in database (shows log insertion order),
  2. [sw:push]
  3. unix timestamp recorded on device using Date.now(). This is supposed to show the definitive execution order on the device since the log messages are sent to the server and logged there so network conditions will scramble the order. However, the lacking precision (millisecond) of Date.now() prevents to know a definitive execution order of all log messages since some have the same timestamp. Will check tomorrow if I can get more accurate timings inside a service worker to make super sure we know the order in which our service worker code is executed. (But not hugely relevant imo)
  4. randomly generated UUID per incoming notification (for easier tracing)
  5. -
  6. log message
"slow zaps": zapping the same post three times and waiting until notification shows up on device between zaps:
78515 [sw:push] 1704760098114 52b1d2bf-de9a-4f3f-9cc7-8d39942ffac2 - received notification with tag TIP-328086
78516 [sw:push] 1704760098118 52b1d2bf-de9a-4f3f-9cc7-8d39942ffac2 - built-in tag filter: []
78517 [sw:push] 1704760098118 52b1d2bf-de9a-4f3f-9cc7-8d39942ffac2 - found 0 TIP-328086 notifications
78518 [sw:push] 1704760098118 52b1d2bf-de9a-4f3f-9cc7-8d39942ffac2 - found 0 TIP-328086 notifications after manual tag filter
78519 [sw:push] 1704760098118 52b1d2bf-de9a-4f3f-9cc7-8d39942ffac2 - manual tag filter: []
78520 [sw:push] 1704760098118 52b1d2bf-de9a-4f3f-9cc7-8d39942ffac2 - TIP-328086 notifications replace previous notifications
78521 [sw:push] 1704760098126 52b1d2bf-de9a-4f3f-9cc7-8d39942ffac2 - closing existing notifications
78522 [sw:push] 1704760098126 52b1d2bf-de9a-4f3f-9cc7-8d39942ffac2 - show notification with title "your post stacked 4200 sats"

78523 [sw:push] 1704760099854 09ae56c0-15e6-4385-9414-dda7b5df93c1 - received notification with tag TIP-328086
78524 [sw:push] 1704760099859 09ae56c0-15e6-4385-9414-dda7b5df93c1 - found 1 TIP-328086 notifications
78525 [sw:push] 1704760099859 09ae56c0-15e6-4385-9414-dda7b5df93c1 - manual tag filter: ["TIP-328086"]
78526 [sw:push] 1704760099859 09ae56c0-15e6-4385-9414-dda7b5df93c1 - found 1 TIP-328086 notifications after manual tag filter
78527 [sw:push] 1704760099859 09ae56c0-15e6-4385-9414-dda7b5df93c1 - built-in tag filter: ["TIP-328086"]
78528 [sw:push] 1704760099859 09ae56c0-15e6-4385-9414-dda7b5df93c1 - TIP-328086 notifications replace previous notifications
78529 [sw:push] 1704760099866 09ae56c0-15e6-4385-9414-dda7b5df93c1 - closing existing notifications
78530 [sw:push] 1704760099866 09ae56c0-15e6-4385-9414-dda7b5df93c1 - show notification with title "your post stacked 4300 sats"

78531 [sw:push] 1704760102520 be2ede18-cb9e-4e12-bb8e-1ae58c482145 - received notification with tag TIP-328086
78532 [sw:push] 1704760102526 be2ede18-cb9e-4e12-bb8e-1ae58c482145 - built-in tag filter: ["TIP-328086","TIP-328086"]
78533 [sw:push] 1704760102526 be2ede18-cb9e-4e12-bb8e-1ae58c482145 - found 2 TIP-328086 notifications after manual tag filter
78534 [sw:push] 1704760102526 be2ede18-cb9e-4e12-bb8e-1ae58c482145 - found 2 TIP-328086 notifications
78535 [sw:push] 1704760102526 be2ede18-cb9e-4e12-bb8e-1ae58c482145 - manual tag filter: ["TIP-328086","TIP-328086"]
78536 [sw:push] 1704760102527 be2ede18-cb9e-4e12-bb8e-1ae58c482145 - TIP-328086 notifications replace previous notifications
78537 [sw:push] 1704760102533 be2ede18-cb9e-4e12-bb8e-1ae58c482145 - closing existing notifications
78538 [sw:push] 1704760102533 be2ede18-cb9e-4e12-bb8e-1ae58c482145 - show notification with title "your post stacked 4400 sats"

Conclusions:

"fast zaps": multiple zaps in quick succession
78707 [sw:push] 1704761438301 c9213c71-2b6f-42f0-a354-1d13187c7443 - received notification with tag TIP-328086
78708 [sw:push] 1704761438302 5da86de2-a182-4094-87c9-d31f024e54c8 - received notification with tag TIP-328086
78709 [sw:push] 1704761438325 c9213c71-2b6f-42f0-a354-1d13187c7443 - found 0 TIP-328086 notifications
78710 [sw:push] 1704761438325 c9213c71-2b6f-42f0-a354-1d13187c7443 - built-in tag filter: []
78711 [sw:push] 1704761438325 c9213c71-2b6f-42f0-a354-1d13187c7443 - found 0 TIP-328086 notifications after manual tag filter
78712 [sw:push] 1704761438325 c9213c71-2b6f-42f0-a354-1d13187c7443 - manual tag filter: []
78713 [sw:push] 1704761438326 c9213c71-2b6f-42f0-a354-1d13187c7443 - TIP-328086 notifications replace previous notifications
78714 [sw:push] 1704761438327 5da86de2-a182-4094-87c9-d31f024e54c8 - found 0 TIP-328086 notifications
78715 [sw:push] 1704761438327 5da86de2-a182-4094-87c9-d31f024e54c8 - found 0 TIP-328086 notifications after manual tag filter
78716 [sw:push] 1704761438327 5da86de2-a182-4094-87c9-d31f024e54c8 - built-in tag filter: []
78717 [sw:push] 1704761438327 5da86de2-a182-4094-87c9-d31f024e54c8 - manual tag filter: []
78718 [sw:push] 1704761438327 5da86de2-a182-4094-87c9-d31f024e54c8 - TIP-328086 notifications replace previous notifications
78719 [sw:push] 1704761438460 c9213c71-2b6f-42f0-a354-1d13187c7443 - closing existing notifications
78720 [sw:push] 1704761438460 c9213c71-2b6f-42f0-a354-1d13187c7443 - show notification with title "your post stacked 6600 sats"
78721 [sw:push] 1704761438460 5da86de2-a182-4094-87c9-d31f024e54c8 - closing existing notifications
78722 [sw:push] 1704761438460 5da86de2-a182-4094-87c9-d31f024e54c8 - show notification with title "your post stacked 6700 sats"
78723 [sw:push] 1704761438666 a6a9b495-fd34-410d-9244-d74dfeb9d82c - received notification with tag TIP-328086
78726 [sw:push] 1704761439557 a857a2d7-067d-406d-82ef-b8d8cf66bd0b - received notification with tag TIP-328086
78725 [sw:push] 1704761439558 c77d7b27-d99b-4ebf-a13a-a977e9572fce - received notification with tag TIP-328086
78724 [sw:push] 1704761439557 a3578425-94a8-4c16-96c0-7dfd085e2fe1 - received notification with tag TIP-328086
78727 [sw:push] 1704761439650 a6a9b495-fd34-410d-9244-d74dfeb9d82c - found 2 TIP-328086 notifications
78728 [sw:push] 1704761439650 a6a9b495-fd34-410d-9244-d74dfeb9d82c - built-in tag filter: ["TIP-328086","TIP-328086"]
78729 [sw:push] 1704761439683 a3578425-94a8-4c16-96c0-7dfd085e2fe1 - found 2 TIP-328086 notifications
78732 [sw:push] 1704761439685 a3578425-94a8-4c16-96c0-7dfd085e2fe1 - built-in tag filter: ["TIP-328086","TIP-328086"]
78730 [sw:push] 1704761439651 a6a9b495-fd34-410d-9244-d74dfeb9d82c - found 2 TIP-328086 notifications after manual tag filter
78731 [sw:push] 1704761439651 a6a9b495-fd34-410d-9244-d74dfeb9d82c - manual tag filter: ["TIP-328086","TIP-328086"]
78733 [sw:push] 1704761439653 a6a9b495-fd34-410d-9244-d74dfeb9d82c - TIP-328086 notifications replace previous notifications
78734 [sw:push] 1704761439685 a3578425-94a8-4c16-96c0-7dfd085e2fe1 - manual tag filter: ["TIP-328086","TIP-328086"]
78735 [sw:push] 1704761439686 a857a2d7-067d-406d-82ef-b8d8cf66bd0b - found 2 TIP-328086 notifications
78736 [sw:push] 1704761439685 a3578425-94a8-4c16-96c0-7dfd085e2fe1 - TIP-328086 notifications replace previous notifications
78737 [sw:push] 1704761439686 a857a2d7-067d-406d-82ef-b8d8cf66bd0b - built-in tag filter: ["TIP-328086","TIP-328086"]
78738 [sw:push] 1704761439686 a857a2d7-067d-406d-82ef-b8d8cf66bd0b - found 2 TIP-328086 notifications after manual tag filter
78739 [sw:push] 1704761439685 a3578425-94a8-4c16-96c0-7dfd085e2fe1 - found 2 TIP-328086 notifications after manual tag filter
78740 [sw:push] 1704761439686 c77d7b27-d99b-4ebf-a13a-a977e9572fce - found 2 TIP-328086 notifications
78741 [sw:push] 1704761439686 a857a2d7-067d-406d-82ef-b8d8cf66bd0b - manual tag filter: ["TIP-328086","TIP-328086"]
78742 [sw:push] 1704761439686 a857a2d7-067d-406d-82ef-b8d8cf66bd0b - TIP-328086 notifications replace previous notifications
78743 [sw:push] 1704761439686 c77d7b27-d99b-4ebf-a13a-a977e9572fce - built-in tag filter: ["TIP-328086","TIP-328086"]
78744 [sw:push] 1704761439687 c77d7b27-d99b-4ebf-a13a-a977e9572fce - manual tag filter: ["TIP-328086","TIP-328086"]
78745 [sw:push] 1704761439687 c77d7b27-d99b-4ebf-a13a-a977e9572fce - found 2 TIP-328086 notifications after manual tag filter
78746 [sw:push] 1704761439687 c77d7b27-d99b-4ebf-a13a-a977e9572fce - TIP-328086 notifications replace previous notifications
78747 [sw:push] 1704761439726 a6a9b495-fd34-410d-9244-d74dfeb9d82c - closing existing notifications
78748 [sw:push] 1704761439759 a6a9b495-fd34-410d-9244-d74dfeb9d82c - show notification with title "your post stacked 6800 sats"
78749 [sw:push] 1704761439764 a3578425-94a8-4c16-96c0-7dfd085e2fe1 - closing existing notifications
78750 [sw:push] 1704761439770 a3578425-94a8-4c16-96c0-7dfd085e2fe1 - show notification with title "your post stacked 6900 sats"
78751 [sw:push] 1704761439771 a857a2d7-067d-406d-82ef-b8d8cf66bd0b - closing existing notifications
78752 [sw:push] 1704761439771 a857a2d7-067d-406d-82ef-b8d8cf66bd0b - show notification with title "your post stacked 7000 sats"
78753 [sw:push] 1704761439774 c77d7b27-d99b-4ebf-a13a-a977e9572fce - closing existing notifications
78754 [sw:push] 1704761439784 c77d7b27-d99b-4ebf-a13a-a977e9572fce - show notification with title "your post stacked 7100 sats"

Conclusions:

  • (most likely) due to bad support of tag, there is a race condition when it comes to getNotifications({ tag }). The first two notifications fetch 0 notifications of this tag, while the remaining notifications all fetch 2 of this tag. This is no problem for zaps since we don't rely on the amount of existing notifications there. We simply want to replace the previous notification. However, this gets more important for notifications like replies.
"slow" replies
78755 [sw:push] 1704761869668 854cf725-a817-4b36-82b5-61f2d2f8d955 - received notification with tag REPLY
78756 [sw:push] 1704761869721 854cf725-a817-4b36-82b5-61f2d2f8d955 - found 0 REPLY notifications
78757 [sw:push] 1704761869721 854cf725-a817-4b36-82b5-61f2d2f8d955 - built-in tag filter: []
78758 [sw:push] 1704761869722 854cf725-a817-4b36-82b5-61f2d2f8d955 - found 0 REPLY notifications after manual tag filter
78759 [sw:push] 1704761869753 854cf725-a817-4b36-82b5-61f2d2f8d955 - manual tag filter: []
78760 [sw:push] 1704761869754 854cf725-a817-4b36-82b5-61f2d2f8d955 - no existing REPLY notifications found
78761 [sw:push] 1704761869755 854cf725-a817-4b36-82b5-61f2d2f8d955 - show notification with title "@036d6006e2 replied to you"

78762 [sw:push] 1704761875673 1391ffc8-55c3-4170-858b-add2cc723eca - received notification with tag REPLY
78763 [sw:push] 1704761875726 1391ffc8-55c3-4170-858b-add2cc723eca - incoming payload.options.data: {"url":"/items/328086?commentId=328102","itemId":328102}
78764 [sw:push] 1704761875724 1391ffc8-55c3-4170-858b-add2cc723eca - found 1 REPLY notifications
78765 [sw:push] 1704761875724 1391ffc8-55c3-4170-858b-add2cc723eca - built-in tag filter: ["REPLY"]
78766 [sw:push] 1704761875724 1391ffc8-55c3-4170-858b-add2cc723eca - found 1 REPLY notifications after manual tag filter
78767 [sw:push] 1704761875724 1391ffc8-55c3-4170-858b-add2cc723eca - manual tag filter: ["REPLY"]
78768 [sw:push] 1704761875726 1391ffc8-55c3-4170-858b-add2cc723eca - using REPLY for control flow
78769 [sw:push] 1704761875726 1391ffc8-55c3-4170-858b-add2cc723eca - notifications: ["{\"url\":\"/items/328086?commentId=328101\",\"itemId\":328101}"]
78770 [sw:push] 1704761875726 1391ffc8-55c3-4170-858b-add2cc723eca - initial amount: 1
78771 [sw:push] 1704761875727 1391ffc8-55c3-4170-858b-add2cc723eca - merged payload: {"url":"/items/328086?commentId=328101","itemId":328101,"amount":2}
78772 [sw:push] 1704761875727 1391ffc8-55c3-4170-858b-add2cc723eca - calculated title: you have 2 new replies
78773 [sw:push] 1704761875727 1391ffc8-55c3-4170-858b-add2cc723eca - closing existing notifications
78774 [sw:push] 1704761875753 1391ffc8-55c3-4170-858b-add2cc723eca - show notification with title "you have 2 new replies"

78775 [sw:push] 1704761881506 3168f30d-a4ff-4dba-b316-a6d885dbe656 - received notification with tag REPLY
78776 [sw:push] 1704761881644 3168f30d-a4ff-4dba-b316-a6d885dbe656 - found 2 REPLY notifications
78777 [sw:push] 1704761881647 3168f30d-a4ff-4dba-b316-a6d885dbe656 - incoming payload.options.data: {"url":"/items/328086?commentId=328103","itemId":328103}
78778 [sw:push] 1704761881645 3168f30d-a4ff-4dba-b316-a6d885dbe656 - more than one notification with tag REPLY found
78779 [sw:push] 1704761881644 3168f30d-a4ff-4dba-b316-a6d885dbe656 - built-in tag filter: ["REPLY","REPLY"]
78780 [sw:push] 1704761881645 3168f30d-a4ff-4dba-b316-a6d885dbe656 - found 2 REPLY notifications after manual tag filter
78781 [sw:push] 1704761881647 3168f30d-a4ff-4dba-b316-a6d885dbe656 - using REPLY for control flow
78782 [sw:push] 1704761881645 3168f30d-a4ff-4dba-b316-a6d885dbe656 - manual tag filter: ["REPLY","REPLY"]
78783 [sw:push] 1704761881647 3168f30d-a4ff-4dba-b316-a6d885dbe656 - notifications: ["{\"url\":\"/items/328086?commentId=328101\",\"itemId\":328101,\"amount\":2}","{\"url\":\"/items/328086?commentId=328101\",\"itemId\":328101}"]
78784 [sw:push] 1704761881647 3168f30d-a4ff-4dba-b316-a6d885dbe656 - initial amount: 2
78785 [sw:push] 1704761881645 3168f30d-a4ff-4dba-b316-a6d885dbe656 - skip bail -- merging notifications with tag REPLY manually
78786 [sw:push] 1704761881649 3168f30d-a4ff-4dba-b316-a6d885dbe656 - merged payload: {"url":"/items/328086?commentId=328101","itemId":328101,"amount":4}
78787 [sw:push] 1704761881649 3168f30d-a4ff-4dba-b316-a6d885dbe656 - calculated title: you have 4 new replies
78788 [sw:push] 1704761881649 3168f30d-a4ff-4dba-b316-a6d885dbe656 - closing existing notifications
78789 [sw:push] 1704761881676 3168f30d-a4ff-4dba-b316-a6d885dbe656 - show notification with title "you have 4 new replies"

78790 [sw:push] 1704761886214 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - received notification with tag REPLY
78791 [sw:push] 1704761886349 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - found 3 REPLY notifications
78792 [sw:push] 1704761886352 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - incoming payload.options.data: {"url":"/items/328086?commentId=328104","itemId":328104}
78793 [sw:push] 1704761886352 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - using REPLY for control flow
78794 [sw:push] 1704761886351 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - skip bail -- merging notifications with tag REPLY manually
78795 [sw:push] 1704761886349 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - built-in tag filter: ["REPLY","REPLY","REPLY"]
78796 [sw:push] 1704761886350 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - found 3 REPLY notifications after manual tag filter
78797 [sw:push] 1704761886352 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - notifications: ["{\"url\":\"/items/328086?commentId=328101\",\"itemId\":328101,\"amount\":4}","{\"url\":\"/items/328086?commentId=328101\",\"itemId\":328101,\"amount\":2}","{\"url\":\"/items/328086?commentId=328101\",\"itemId\":328101}"]
78798 [sw:push] 1704761886350 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - manual tag filter: ["REPLY","REPLY","REPLY"]
78799 [sw:push] 1704761886352 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - initial amount: 4
78800 [sw:push] 1704761886351 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - more than one notification with tag REPLY found
78801 [sw:push] 1704761886354 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - merged payload: {"url":"/items/328086?commentId=328101","itemId":328101,"amount":7}
78802 [sw:push] 1704761886354 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - calculated title: you have 7 new replies
78803 [sw:push] 1704761886354 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - closing existing notifications
78804 [sw:push] 1704761886371 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - show notification with title "you have 7 new replies"

signal-2024-01-09-020353

Conclusions:

  • We're showing the wrong amount of replies because we're adding the amount of existing notifications basically twice. Relevant log messages (they should make clear that this is what is happening):
78796 [sw:push] 1704761886350 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - found 3 REPLY notifications after manual tag filter
78797 [sw:push] 1704761886352 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - notifications: ["{\"url\":\"/items/328086?commentId=328101\",\"itemId\":328101,\"amount\":4}","{\"url\":\"/items/328086?commentId=328101\",\"itemId\":328101,\"amount\":2}","{\"url\":\"/items/328086?commentId=328101\",\"itemId\":328101}"]
78798 [sw:push] 1704761886350 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - manual tag filter: ["REPLY","REPLY","REPLY"]
78799 [sw:push] 1704761886352 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - initial amount: 4
78800 [sw:push] 1704761886351 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - more than one notification with tag REPLY found
78801 [sw:push] 1704761886354 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - merged payload: {"url":"/items/328086?commentId=328101","itemId":328101,"amount":7}
78802 [sw:push] 1704761886354 2e9b5457-02d1-4db1-a07c-a35ebf6e473a - calculated title: you have 7 new replies

Or in other words: The data of the last notification has amount set to the amount of existing notifications that were seen when this notification was created (this works well on Android due to proper support of tag and close). However, since close doesn't work, the previous notifications still exist and we just add them again in our reducer for merging notifications:

// this should reflect the amount of notifications that were already merged before
log(`[sw:push] ${Date.now()} ${nid} - notifications: ${JSON.stringify(currentNotifications.map(({ data }) => JSON.stringify(data)))}`)
const initialAmount = currentNotifications[0].data?.amount || 1
log(`[sw:push] ${Date.now()} ${nid} - initial amount: ${initialAmount}`)
const mergedPayload = currentNotifications.reduce((acc, { data }) => {
  let newAmount, newSats
  if (AMOUNT_TAGS.includes(compareTag)) {
    newAmount = acc.amount + 1
  }
  if (SUM_SATS_TAGS.includes(compareTag)) {
    newSats = acc.sats + data.sats
  }
  const newPayload = { ...data, amount: newAmount, sats: newSats }
  return newPayload
}, { ...incomingData, amount: initialAmount })

I think that we show the wrong amount of replies is fixable on our side by adding more iOS-specific logic. Will do this tomorrow.

replying and closing notifications manually (swiping them away)
78865 [sw:push] 1704764179022 aedf1d79-2945-4db5-9936-ecaa8531b9a1 - found 0 REPLY notifications after manual tag filter
78866 [sw:push] 1704764178931 aedf1d79-2945-4db5-9936-ecaa8531b9a1 - received notification with tag REPLY
78867 [sw:push] 1704764179020 aedf1d79-2945-4db5-9936-ecaa8531b9a1 - found 0 REPLY notifications
78868 [sw:push] 1704764179020 aedf1d79-2945-4db5-9936-ecaa8531b9a1 - built-in tag filter: []
78869 [sw:push] 1704764179022 aedf1d79-2945-4db5-9936-ecaa8531b9a1 - manual tag filter: []
78870 [sw:push] 1704764179025 aedf1d79-2945-4db5-9936-ecaa8531b9a1 - show notification with title "@036d6006e2 replied to you"
78871 [sw:push] 1704764179024 aedf1d79-2945-4db5-9936-ecaa8531b9a1 - no existing REPLY notifications found

78872 [sw:push] 1704764183947 d9b05a59-7f0e-454b-be62-e5faeb141a64 - received notification with tag REPLY
78873 [sw:push] 1704764183955 d9b05a59-7f0e-454b-be62-e5faeb141a64 - found 1 REPLY notifications
78874 [sw:push] 1704764183955 d9b05a59-7f0e-454b-be62-e5faeb141a64 - built-in tag filter: ["REPLY"]
78875 [sw:push] 1704764183958 d9b05a59-7f0e-454b-be62-e5faeb141a64 - incoming payload.options.data: {"url":"/items/328086?commentId=328117","itemId":328117}
78876 [sw:push] 1704764183956 d9b05a59-7f0e-454b-be62-e5faeb141a64 - found 1 REPLY notifications after manual tag filter
78877 [sw:push] 1704764183958 d9b05a59-7f0e-454b-be62-e5faeb141a64 - using REPLY for control flow
78878 [sw:push] 1704764183956 d9b05a59-7f0e-454b-be62-e5faeb141a64 - manual tag filter: ["REPLY"]
78879 [sw:push] 1704764183958 d9b05a59-7f0e-454b-be62-e5faeb141a64 - notifications: ["{\"url\":\"/items/328086?commentId=328116\",\"itemId\":328116}"]
78880 [sw:push] 1704764183958 d9b05a59-7f0e-454b-be62-e5faeb141a64 - initial amount: 1
78881 [sw:push] 1704764183959 d9b05a59-7f0e-454b-be62-e5faeb141a64 - merged payload: {"url":"/items/328086?commentId=328116","itemId":328116,"amount":2}
78882 [sw:push] 1704764183959 d9b05a59-7f0e-454b-be62-e5faeb141a64 - calculated title: you have 2 new replies
78883 [sw:push] 1704764183959 d9b05a59-7f0e-454b-be62-e5faeb141a64 - closing existing notifications
78884 [sw:push] 1704764183965 d9b05a59-7f0e-454b-be62-e5faeb141a64 - show notification with title "you have 2 new replies"

78885 [sw:push] 1704764186146 967f421d-be9c-4440-9da0-12d67dc775f2 - received notification with tag REPLY
78889 [sw:push] 1704764186152 967f421d-be9c-4440-9da0-12d67dc775f2 - built-in tag filter: ["REPLY","REPLY"]
78888 [sw:push] 1704764186152 967f421d-be9c-4440-9da0-12d67dc775f2 - manual tag filter: ["REPLY","REPLY"]
78886 [sw:push] 1704764186152 967f421d-be9c-4440-9da0-12d67dc775f2 - found 2 REPLY notifications after manual tag filter
78887 [sw:push] 1704764186153 967f421d-be9c-4440-9da0-12d67dc775f2 - more than one notification with tag REPLY found
78890 [sw:push] 1704764186152 967f421d-be9c-4440-9da0-12d67dc775f2 - found 2 REPLY notifications
78891 [sw:push] 1704764186155 967f421d-be9c-4440-9da0-12d67dc775f2 - incoming payload.options.data: {"url":"/items/328086?commentId=328118","itemId":328118}
78893 [sw:push] 1704764186153 967f421d-be9c-4440-9da0-12d67dc775f2 - skip bail -- merging notifications with tag REPLY manually
78892 [sw:push] 1704764186155 967f421d-be9c-4440-9da0-12d67dc775f2 - using REPLY for control flow
78894 [sw:push] 1704764186155 967f421d-be9c-4440-9da0-12d67dc775f2 - notifications: ["{\"url\":\"/items/328086?commentId=328116\",\"itemId\":328116,\"amount\":2}","{\"url\":\"/items/328086?commentId=328116\",\"itemId\":328116}"]
78895 [sw:push] 1704764186156 967f421d-be9c-4440-9da0-12d67dc775f2 - merged payload: {"url":"/items/328086?commentId=328116","itemId":328116,"amount":4}
78896 [sw:push] 1704764186155 967f421d-be9c-4440-9da0-12d67dc775f2 - initial amount: 2
78897 [sw:push] 1704764186156 967f421d-be9c-4440-9da0-12d67dc775f2 - calculated title: you have 4 new replies

// closing second notification

78898 [sw:push] 1704764186156 967f421d-be9c-4440-9da0-12d67dc775f2 - closing existing notifications
78899 [sw:push] 1704764186161 967f421d-be9c-4440-9da0-12d67dc775f2 - show notification with title "you have 4 new replies"
78900 [sw:push] 1704764208007 7a729557-6bba-4b28-abfb-489cbe211f58 - received notification with tag REPLY
78901 [sw:push] 1704764208078 7a729557-6bba-4b28-abfb-489cbe211f58 - found 2 REPLY notifications
78902 [sw:push] 1704764208081 7a729557-6bba-4b28-abfb-489cbe211f58 - more than one notification with tag REPLY found
78903 [sw:push] 1704764208081 7a729557-6bba-4b28-abfb-489cbe211f58 - skip bail -- merging notifications with tag REPLY manually
78904 [sw:push] 1704764208079 7a729557-6bba-4b28-abfb-489cbe211f58 - found 2 REPLY notifications after manual tag filter
78905 [sw:push] 1704764208078 7a729557-6bba-4b28-abfb-489cbe211f58 - built-in tag filter: ["REPLY","REPLY"]
78906 [sw:push] 1704764208079 7a729557-6bba-4b28-abfb-489cbe211f58 - manual tag filter: ["REPLY","REPLY"]
78907 [sw:push] 1704764208083 7a729557-6bba-4b28-abfb-489cbe211f58 - incoming payload.options.data: {"url":"/items/328086?commentId=328119","itemId":328119}
78908 [sw:push] 1704764208083 7a729557-6bba-4b28-abfb-489cbe211f58 - using REPLY for control flow
78909 [sw:push] 1704764208083 7a729557-6bba-4b28-abfb-489cbe211f58 - notifications: ["{\"url\":\"/items/328086?commentId=328116\",\"itemId\":328116,\"amount\":4}","{\"url\":\"/items/328086?commentId=328116\",\"itemId\":328116}"]
78910 [sw:push] 1704764208083 7a729557-6bba-4b28-abfb-489cbe211f58 - initial amount: 4
78911 [sw:push] 1704764208086 7a729557-6bba-4b28-abfb-489cbe211f58 - merged payload: {"url":"/items/328086?commentId=328116","itemId":328116,"amount":6}
78912 [sw:push] 1704764208086 7a729557-6bba-4b28-abfb-489cbe211f58 - calculated title: you have 6 new replies
78913 [sw:push] 1704764208086 7a729557-6bba-4b28-abfb-489cbe211f58 - closing existing notifications
78914 [sw:push] 1704764208087 7a729557-6bba-4b28-abfb-489cbe211f58 - show notification with title "you have 6 new replies"

Conclusion:

  • closing notification manually is correctly registered: getNotifications({ tag }) does no longer show this notification. This is the behavior we would like to also see when we use the Notification API (Notification.close()).

Will add a comment to the WebKit bug report tomorrow and ask for clarification about the behavior of Notification.close() and getNotifications({ tag }) since what was mentioned there does not reflect what we are seeing:

On iOS Safari, ServiceWorkerRegistration.getNotifications() appears to always return an empty array, so there's no way to compare that behaviour.

@SatsAllDay
Copy link
Contributor Author

Just leaving a note that this seems to have been happening a lot more than usual lately (past few days).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants