-
Notifications
You must be signed in to change notification settings - Fork 121
[POS][Local Catalog] Ensure we only run one sync at a time per site #16100
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
[POS][Local Catalog] Ensure we only run one sync at a time per site #16100
Conversation
|
@jaclync I've realised the ServiceLocator pattern here is broken – if you log out and back in again with a different account, it'll still use the previous credentials, because the static var won't be replaced in that scenario. I'll handle this on Monday, but it won't change the fundamentals of the PR – so I'm marking it ready for review anyway. |
|
|
jaclync
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving some initial thoughts on the ServiceLocator usage!
| // Configure POS catalog sync coordinator for local catalog syncing | ||
| if ServiceLocator.featureFlagService.isFeatureFlagEnabled(.pointOfSaleLocalCatalogi1) { | ||
| posCatalogSyncCoordinator = createPOSCatalogSyncCoordinator() | ||
| posCatalogSyncCoordinator = ServiceLocator.posCatalogSyncCoordinator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I felt like the move to a ServiceLocator static singleton could open a can of worms - handling login/login states, unit testing caveats, etc., which add to the complexity of the sync coordinator. What do you think of alternatives, like keeping a dictionary from site ID to catalog sync coordinator, then resetting it in removeViewControllers, all within MainTabBarController? This way, each sync coordinator is associated with a single site ID, making it easier to maintain. The changes in POSCatalogSyncCoordinator could become keeping track of whether a full sync is ongoing, and guard on this state at the beginning of a full sync.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, perhaps it's wrong.
I thought it should be on service locator, looking ahead to background updates. We'll need to deal with the sync coordinator in the background and in the foreground, and there really ought to only be one at a time.
For example, we don't want there to be a full sync in progress, then the app be backgrounded, a BGAppRefreshTask run, and start another full sync from that task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, there should certainly just be one single sync coordinator, I was mostly wondering if we could implement the singleton in a different way from a "static singleton" in ServiceLocator. If you think ServiceLocator is the best option, let's go for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about this approach?
By exposing it from AuthenticatedState, we make a new one whenever we log in or switch sites... but it's still long-lived, staying around as long as we're logged in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about this approach?
Looks nice, thanks for the updates! I like that its life cycle is now tied to the authenticated state. I left a separate comment about resetting it on logout.
By exposing it from AuthenticatedState, we make a new one whenever we log in or switch sites...
From my understanding and quick testing, switching stores shouldn't trigger a reinitialization of AuthenticatedState, just logging in.
| if ongoingSyncs.contains(siteID) { | ||
| DDLogInfo("⚠️ POSCatalogSyncCoordinator: Sync already in progress for site \(siteID)") | ||
| throw POSCatalogSyncError.syncAlreadyInProgress(siteID: siteID) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about moving it to shouldPerformFullSync?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think probably better to keep it where it is. There could be some gap between calling shouldPerform and perform, which would make this check fail.
…nto woomob-1252-ensure-only-one-sync-at-a-time-per-site
jaclync
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works as expected! ![]()
| grdbManager: ServiceLocator.grdbManager | ||
| ) | ||
| } else { | ||
| posCatalogSyncCoordinator = nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Do we also want to reset posCatalogSyncCoordinator in willLeave when the merchant logs out? Perhaps can call a reset / onLogout function to cancel ongoing syncs and reset the database (can also be a future task).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add a ticket for this. We may just want to let syncs complete though.
We need to check what the current behaviour with Core Data is, and what our requirements are, esp legal/privacy for clearing the db. Jirka mentioned that for GDPR compliance we may need to clear the database on any logout, but I'm not sure about whether our data is really personal enough to require that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to check what the current behaviour with Core Data is
The app has been deleting all stored data in all tables in the database on logout:
| ServiceLocator.storageManager.reset() |
and
woocommerce-ios/Modules/Sources/Storage/CoreData/CoreDataManager.swift
Lines 152 to 163 in 3914fc5
| public func reset(onCompletion: (() -> Void)?) { | |
| /// Delete all objects in the background context to avoid discrepancy with the view context | |
| /// The view context will get updated automatically once the changes are saved to the persistent container. | |
| performAndSave({ storage in | |
| let backgroundContext = storage as! NSManagedObjectContext | |
| /// persist self to complete deleting objects | |
| self.deleteAllStoredObjects(in: backgroundContext) | |
| }, completion: { | |
| DDLogVerbose("💣 [CoreDataManager] Stack Destroyed!") | |
| onCompletion?() | |
| }, on: .main) | |
| } |
thus I was assuming that we are going to reset the database in GRDB as well. I don't know much about the legal requirements, but generally as a user I expect all data to be cleared when logging out manually from an app. If it's a shared device, leaving store data after logging out might not be ideal even though there is no sensitve information.
What do you think are the use cases of keeping the data after logout? Is it for the site credentials use case where the merchant needs to log out and in for different sites? I think a proper multi-site support would be preferred. Since we're deleting all the data at the beginning of each full sync and a full sync is triggered after logging in to an eligible site, I'm not sure how the previous data before login could be used (maybe in case the latest full sync fails?). Would like to hear your perspectives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, thanks for the detail, we should follow that existing approach.
What do you think are the use cases of keeping the data after logout? Is it for the site credentials use case where the merchant needs to log out and in for different sites? I think a proper multi-site support would be preferred.
This, and yes I agree that something where you could be logged in to multiple sites with site credentials at the same time would be better.
Since we're deleting all the data at the beginning of each full sync and a full sync is triggered after logging in to an eligible site, I'm not sure how the previous data before login could be used (maybe in case the latest full sync fails?). Would like to hear your perspectives.
This comes more into the existing site switching for JP users...
We're only deleting all data for full syncs while the products aren't site-scoped. When we resolve that, we'd only delete the site's data when you switch to it.
At that point, we wouldn't need to redo a full-sync in this scenario:
- Log in with WP.com to some site for the first time – full sync site A
- Switch to another site – full sync site B
- Switch back to site A – no need to full sync here, we already have it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See WOOMOB-1322 for resetting the database
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to be consistent with how other storage data are handled on logout 👍
| // Configure POS catalog sync coordinator for local catalog syncing | ||
| if ServiceLocator.featureFlagService.isFeatureFlagEnabled(.pointOfSaleLocalCatalogi1) { | ||
| posCatalogSyncCoordinator = createPOSCatalogSyncCoordinator() | ||
| posCatalogSyncCoordinator = ServiceLocator.posCatalogSyncCoordinator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about this approach?
Looks nice, thanks for the updates! I like that its life cycle is now tied to the authenticated state. I left a separate comment about resetting it on logout.
By exposing it from AuthenticatedState, we make a new one whenever we log in or switch sites...
From my understanding and quick testing, switching stores shouldn't trigger a reinitialization of AuthenticatedState, just logging in.
Yes, you're right. It doesn't need to happen on switching store, because the credentials are the same. |

Merge after: #16099
Part of: WOOMOB-1252
Description
This PR updates the
POSCatalogSyncCoordinatorto prevent simultaneous syncs for the same site, while allowing simultaneous syncs for different sites.This may be over the top... but is potentially easier to manage long term than cancelling syncs.
It does this by:
performFullSyncis safe to call concurrentlyperformFullSyncfor a site already being synced.Steps to reproduce
Screenshots
RELEASE-NOTES.txtif necessary.