Migrate push registrations back to WPCom when the Woo-driven system is disabled#16183
Conversation
Generated by 🚫 Danger |
437ccdf to
0119ac6
Compare
|
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## release/25.1 #16183 +/- ##
==================================================
+ Coverage 42.49% 42.52% +0.02%
- Complexity 13893 13917 +24
==================================================
Files 2529 2529
Lines 146006 146082 +76
Branches 21322 21347 +25
==================================================
+ Hits 62051 62125 +74
+ Misses 77645 77637 -8
- Partials 6310 6320 +10 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| private fun Preferences.registeredSiteIds(): Set<Long> = asMap().keys | ||
| .mapNotNull { key -> | ||
| key.name | ||
| .takeIf { it.startsWith(PUSH_TOKEN_KEY_PREFIX) && !it.startsWith(PUSH_TOKEN_VALUE_KEY_PREFIX) } |
There was a problem hiding this comment.
No behavior change here. The old parsing in getWooPushRegisteredSiteIds already excluded push_token_value_* keys, but only as a side effect: removePrefix("push_token_") left "value_123", which fails toLongOrNull() and gets dropped. This condition states that rule explicitly instead of relying on the leftover string not parsing as a number. Same site IDs come out either way.
hichamboushaba
left a comment
There was a problem hiding this comment.
Thanks @irfano, code looks good, there is just one question to clarify before approving.
| val shouldForce = trigger == Trigger.TOKEN_REFRESH | ||
|
|
||
| if (featureFlagRepository.isEnabled(FeatureFlag.WOO_SELF_DRIVEN_PUSH_NOTIFICATIONS_M1)) { | ||
| pushNotificationRepository.clearWooPushRegistrationsForStaleToken(token) |
There was a problem hiding this comment.
❓ isn't the existing logic in
RegisterDevice, and I'm trying to understand why we need to remove the registration state instead of what shouldRegisterWooPushForSite does.
There was a problem hiding this comment.
shouldRegisterWooPushForSite decides whether to retry the registration, but it doesn't change the registration state between attempts. Until a retry succeeds, the site still counts as Woo-registered. If the failure is persistent, this can last forever, and two problems remain during that time:
- The status keeps saying "registered". For app-password and Jetpack CP sites this also keeps the "Enable push notifications" entry points hidden, so the user can't recover from within the app, the only fix is clearing app data. And Woo push is the only channel these sites have.
NotificationMessageHandlerkeeps dropping incoming WP.com notifications for the site. The Woo registration holds the dead token, so if WP.com is actually sending, e.g. when the disable call failed at registration time, those notifications never show up.
Clearing on token mismatch makes the local state match reality: the site isn't registered until a registration with the current token succeeds. It doesn't replace the staleness check, re-registration is still driven by shouldRegisterWooPushForSite for non-forced triggers and locale changes.
There was a problem hiding this comment.
Thanks, that makes sense. My remaining concern is mostly with the flow here:
clearWooPushRegistrationsForStaleToken(token)
shouldRegisterWooPushForSite(token, site.siteId)shouldRegisterWooPushForSite already checks registration.token != currentToken, but after the up-front clear, stale-token cases become registration == null instead. Could we keep the stale-token cleanup closer to the per-site registration decision?
Something like:
val shouldRegisterSite = shouldForce ||
pushNotificationRepository.shouldRegisterWooPushForSite(token, site.siteId)
if (shouldRegisterSite) {
pushNotificationRepository.clearWooPushRegistrationForStaleToken(site.siteId, token)
pushNotificationRepository.registerPushTokenInWooCoreSystem(...)
}The reason I find this easier to reason about is that the same per-site flow owns both decisions: first decide whether this site needs registration, then clear stale local state only as part of that registration path. That makes the token-mismatch case explicit without having a separate pre-pass that changes what shouldRegisterWooPushForSite sees. Not blocking.
There was a problem hiding this comment.
Agreed, moved the cleanup into the per-site path in eca6fdb.
hichamboushaba
left a comment
There was a problem hiding this comment.
Thanks @irfano, pre-approving, I left one last comment on the previous thread, but it's not a blocker.

Description
When the
woo_self_driven_push_notifications_m1feature flag is disabled remotely, devices that already registered with the Woo Core push system keep their local Woo registration. That state suppresses the WP.com fallback (the app drops incoming WP.com notifications for Woo-registered sites, and WP.com settings for those sites stay disabled), so those users can end up without notifications, permanently after an FCM token rotation. This PR adds recovery logic for both paths, following the approach suggested by Hicham (supersedes #16166):Flag on: before re-registering, local Woo registrations whose stored token no longer matches the current FCM token are cleared, so a rotated token can't leave stale state behind (mirrors the iOS behavior of clearing registered site IDs on token change).
Flag off: Woo push registrations are migrated back to WP.com:
flowchart TD A["RegisterDevice runs with current FCM token"] --> B{"Woo self-driven push flag on?"} B -- yes --> C["Clear local Woo registrations whose stored token != current FCM token"] C --> D["Woo registration for sites, as today"] D --> E["Successful registrations save current token and disable WP.com notifications"] B -- no --> G{"Trigger is SITE_SWITCH?"} G -- yes --> H["Skip migration"] G -- no --> I["Find locally Woo-registered site IDs"] I --> J{"Any Woo-registered sites?"} J -- no --> K["Nothing to migrate"] J -- yes --> L["Determine WP.com fallback sites: visible + full Jetpack, with WP.com account"] L --> M["Ensure WP.com device is registered"] M --> N["Re-enable WP.com notifications for fallback sites"] N --> O{"WP.com took over successfully?"} O -- yes --> P["Unregister ALL Woo-registered sites from Woo Core"] O -- no --> Q["Unregister only sites without a WP.com fallback"] P --> R["Local state cleared per site only after server delete succeeds"] Q --> RAlso adds
wpcom_device_enable_push_notifications_success/errorevents, mirroring the existing disable events.Test Steps
Use a debug build with a Jetpack-connected store on Woo Core 10.9.2. Until 10.9.2 is released, either install a nightly/dev build of the plugin or temporarily lower
PUSH_NOTIFICATIONS_MIN_WC_VERSIONto10.9.1; on older versions the app treats even successfully registered sites as unregistered, which skews the results. The flag can be toggled from Developer Options → Feature Flags. To force an FCM token rotation, apply this debug receiver patch and use the adb broadcast from #16166.Migration (flag off):
Migrating Woo push registrations back to WP.com...→WPCom notifications enabled for sites...→Woo Core push token deleted for site....Token rotation while the flag is off (the original blackout scenario):
Stale token cleanup (flag on):
Cleared stale Woo Core push registration for site...followed by re-registration with the new token.Site-credentials store (flag off): repeat the migration steps with a site-credentials login; verify no WP.com calls are made and the Woo token is still deleted.
Images/gif
N/A
RELEASE-NOTES.txtif necessary. Use the "[Internal]" label for non-user-facing changes.