Skip to content

Commit 1d4ebce

Browse files
authored
[Local Catalog] Update full/incremental sync to have consistent interface (#16187)
2 parents dd32ad1 + ea8efcb commit 1d4ebce

File tree

5 files changed

+169
-133
lines changed

5 files changed

+169
-133
lines changed

Modules/Sources/PointOfSale/Utils/PreviewHelpers.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -609,16 +609,12 @@ final class POSPreviewCatalogSettingsService: POSCatalogSettingsServiceProtocol
609609
}
610610

611611
final class POSPreviewCatalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol {
612-
func performFullSync(for siteID: Int64) async throws {
612+
func performFullSyncIfApplicable(for siteID: Int64, maxAge: TimeInterval) async throws {
613613
// Simulates a full sync operation with a 1 second delay.
614614
try await Task.sleep(nanoseconds: 1_000_000_000)
615615
}
616616

617-
func shouldPerformFullSync(for siteID: Int64, maxAge: TimeInterval) async -> Bool {
618-
true
619-
}
620-
621-
func performIncrementalSyncIfApplicable(for siteID: Int64, forceSync: Bool) async throws {
617+
func performIncrementalSyncIfApplicable(for siteID: Int64, maxAge: TimeInterval) async throws {
622618
// Simulates an incremental sync operation with a 0.5 second delay.
623619
try await Task.sleep(nanoseconds: 500_000_000)
624620
}

Modules/Sources/Yosemite/Tools/POS/POSCatalogSyncCoordinator.swift

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,41 @@ import Storage
44
import GRDB
55

66
public protocol POSCatalogSyncCoordinatorProtocol {
7-
/// Performs a full catalog sync for the specified site
8-
/// - Parameter siteID: The site ID to sync catalog for
9-
/// - Throws: POSCatalogSyncError.syncAlreadyInProgress if a sync is already running for this site
10-
func performFullSync(for siteID: Int64) async throws
11-
12-
/// Determines if a full sync should be performed based on the age of the last sync
7+
/// Performs a full catalog sync if applicable for the specified site
138
/// - Parameters:
14-
/// - siteID: The site ID to check
9+
/// - siteID: The site ID to sync catalog for
1510
/// - maxAge: Maximum age before a sync is considered stale
16-
/// - Returns: True if a sync should be performed
17-
func shouldPerformFullSync(for siteID: Int64, maxAge: TimeInterval) async -> Bool
11+
/// - Throws: POSCatalogSyncError.syncAlreadyInProgress if a sync is already running for this site
12+
func performFullSyncIfApplicable(for siteID: Int64, maxAge: TimeInterval) async throws
1813

1914
/// Performs an incremental sync if applicable based on sync conditions
2015
/// - Parameters:
2116
/// - siteID: The site ID to sync catalog for
22-
/// - forceSync: Whether to bypass age checks and always sync
17+
/// - maxAge: Maximum age before a sync is considered stale
2318
/// - Throws: POSCatalogSyncError.syncAlreadyInProgress if a sync is already running for this site
2419
//periphery:ignore - remove ignore comment when incremental sync is integrated with POS
25-
func performIncrementalSyncIfApplicable(for siteID: Int64, forceSync: Bool) async throws
20+
func performIncrementalSyncIfApplicable(for siteID: Int64, maxAge: TimeInterval) async throws
21+
}
22+
23+
public extension POSCatalogSyncCoordinatorProtocol {
24+
func performFullSync(for siteID: Int64) async throws {
25+
try await performFullSyncIfApplicable(for: siteID, maxAge: .zero)
26+
}
27+
28+
func performIncrementalSync(for siteID: Int64) async throws {
29+
try await performIncrementalSyncIfApplicable(for: siteID, maxAge: .zero)
30+
}
2631
}
2732

2833
public enum POSCatalogSyncError: Error, Equatable {
2934
case syncAlreadyInProgress(siteID: Int64)
35+
case negativeMaxAge
3036
}
3137

3238
public actor POSCatalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol {
3339
private let fullSyncService: POSCatalogFullSyncServiceProtocol
3440
private let incrementalSyncService: POSCatalogIncrementalSyncServiceProtocol
3541
private let grdbManager: GRDBManagerProtocol
36-
private let maxIncrementalSyncAge: TimeInterval
3742
private let catalogSizeLimit: Int
3843
private let catalogSizeChecker: POSCatalogSizeCheckerProtocol
3944

@@ -45,18 +50,24 @@ public actor POSCatalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol {
4550
public init(fullSyncService: POSCatalogFullSyncServiceProtocol,
4651
incrementalSyncService: POSCatalogIncrementalSyncServiceProtocol,
4752
grdbManager: GRDBManagerProtocol,
48-
maxIncrementalSyncAge: TimeInterval = 300,
4953
catalogSizeLimit: Int? = nil,
5054
catalogSizeChecker: POSCatalogSizeCheckerProtocol) {
5155
self.fullSyncService = fullSyncService
5256
self.incrementalSyncService = incrementalSyncService
5357
self.grdbManager = grdbManager
54-
self.maxIncrementalSyncAge = maxIncrementalSyncAge
5558
self.catalogSizeLimit = catalogSizeLimit ?? Constants.defaultSizeLimitForPOSCatalog
5659
self.catalogSizeChecker = catalogSizeChecker
5760
}
5861

59-
public func performFullSync(for siteID: Int64) async throws {
62+
public func performFullSyncIfApplicable(for siteID: Int64, maxAge: TimeInterval) async throws {
63+
guard maxAge >= 0 else {
64+
throw POSCatalogSyncError.negativeMaxAge
65+
}
66+
67+
guard await shouldPerformFullSync(for: siteID, maxAge: maxAge) else {
68+
return
69+
}
70+
6071
if ongoingSyncs.contains(siteID) {
6172
DDLogInfo("⚠️ POSCatalogSyncCoordinator: Sync already in progress for site \(siteID)")
6273
throw POSCatalogSyncError.syncAlreadyInProgress(siteID: siteID)
@@ -82,8 +93,8 @@ public actor POSCatalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol {
8293
/// - siteID: The site ID to check
8394
/// - maxAge: Maximum age before a sync is considered stale
8495
/// - Returns: True if a sync should be performed
85-
public func shouldPerformFullSync(for siteID: Int64, maxAge: TimeInterval) async -> Bool {
86-
return await shouldPerformFullSync(for: siteID, maxAge: maxAge, maxCatalogSize: catalogSizeLimit)
96+
private func shouldPerformFullSync(for siteID: Int64, maxAge: TimeInterval) async -> Bool {
97+
await shouldPerformFullSync(for: siteID, maxAge: maxAge, maxCatalogSize: catalogSizeLimit)
8798
}
8899

89100
private func shouldPerformFullSync(for siteID: Int64, maxAge: TimeInterval, maxCatalogSize: Int) async -> Bool {
@@ -118,33 +129,28 @@ public actor POSCatalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol {
118129
/// Performs an incremental sync if applicable based on sync conditions
119130
/// - Parameters:
120131
/// - siteID: The site ID to sync catalog for
121-
/// - forceSync: Whether to bypass age checks and always sync
132+
/// - maxAge: Maximum age before a sync is considered stale
122133
/// - Throws: POSCatalogSyncError.syncAlreadyInProgress if a sync is already running for this site
123-
public func performIncrementalSyncIfApplicable(for siteID: Int64, forceSync: Bool) async throws {
124-
try await performIncrementalSyncIfApplicable(for: siteID, forceSync: forceSync, maxCatalogSize: catalogSizeLimit)
134+
public func performIncrementalSyncIfApplicable(for siteID: Int64, maxAge: TimeInterval) async throws {
135+
try await performIncrementalSyncIfApplicable(for: siteID, maxAge: maxAge, maxCatalogSize: catalogSizeLimit)
125136
}
126137

127-
private func performIncrementalSyncIfApplicable(for siteID: Int64, forceSync: Bool, maxCatalogSize: Int) async throws {
128-
if ongoingIncrementalSyncs.contains(siteID) {
129-
DDLogInfo("⚠️ POSCatalogSyncCoordinator: Incremental sync already in progress for site \(siteID)")
130-
throw POSCatalogSyncError.syncAlreadyInProgress(siteID: siteID)
138+
private func performIncrementalSyncIfApplicable(for siteID: Int64, maxAge: TimeInterval, maxCatalogSize: Int) async throws {
139+
guard maxAge >= 0 else {
140+
throw POSCatalogSyncError.negativeMaxAge
131141
}
132142

133-
guard await isCatalogSizeWithinLimit(for: siteID, maxCatalogSize: maxCatalogSize) else {
143+
guard await shouldPerformIncrementalSync(for: siteID, maxAge: maxAge, maxCatalogSize: maxCatalogSize) else {
134144
return
135145
}
136146

137-
guard let lastFullSyncDate = await lastFullSyncDate(for: siteID) else {
138-
DDLogInfo("📋 POSCatalogSyncCoordinator: No full sync performed yet for site \(siteID), skipping incremental sync")
139-
return
147+
if ongoingIncrementalSyncs.contains(siteID) {
148+
DDLogInfo("⚠️ POSCatalogSyncCoordinator: Incremental sync already in progress for site \(siteID)")
149+
throw POSCatalogSyncError.syncAlreadyInProgress(siteID: siteID)
140150
}
141151

142-
if !forceSync, let lastIncrementalSyncDate = await lastIncrementalSyncDate(for: siteID) {
143-
let age = Date().timeIntervalSince(lastIncrementalSyncDate)
144-
145-
if age <= maxIncrementalSyncAge {
146-
return DDLogInfo("📋 POSCatalogSyncCoordinator: Last incremental sync for site \(siteID) was \(Int(age))s ago, sync not needed")
147-
}
152+
guard let lastFullSyncDate = await lastFullSyncDate(for: siteID) else {
153+
return
148154
}
149155

150156
ongoingIncrementalSyncs.insert(siteID)
@@ -162,6 +168,28 @@ public actor POSCatalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol {
162168
DDLogInfo("✅ POSCatalogSyncCoordinator completed incremental sync for site \(siteID)")
163169
}
164170

171+
private func shouldPerformIncrementalSync(for siteID: Int64, maxAge: TimeInterval, maxCatalogSize: Int) async -> Bool {
172+
guard await isCatalogSizeWithinLimit(for: siteID, maxCatalogSize: maxCatalogSize) else {
173+
return false
174+
}
175+
176+
guard await lastFullSyncDate(for: siteID) != nil else {
177+
DDLogInfo("📋 POSCatalogSyncCoordinator: No full sync performed yet for site \(siteID), skipping incremental sync")
178+
return false
179+
}
180+
181+
if maxAge > 0, let lastIncrementalSyncDate = await lastIncrementalSyncDate(for: siteID) {
182+
let age = Date().timeIntervalSince(lastIncrementalSyncDate)
183+
184+
if age <= maxAge {
185+
DDLogInfo("📋 POSCatalogSyncCoordinator: Last incremental sync for site \(siteID) was \(Int(age))s ago, sync not needed")
186+
return false
187+
}
188+
}
189+
190+
return true
191+
}
192+
165193
// MARK: - Private
166194

167195
/// Checks if the catalog size is within the specified sync limit

Modules/Tests/PointOfSaleTests/Mocks/MockPOSCatalogSyncCoordinator.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ final class MockPOSCatalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol {
77
var performFullSyncResult: Result<Void, Error> = .success(())
88
var shouldDelayResponse = false
99

10-
func shouldPerformFullSync(for siteID: Int64, maxAge: TimeInterval) async -> Bool {
11-
true
12-
}
13-
14-
func performFullSync(for siteID: Int64) async throws {
10+
func performFullSyncIfApplicable(for siteID: Int64, maxAge: TimeInterval) async throws {
1511
if shouldDelayResponse {
1612
try await Task.sleep(for: .milliseconds(100))
1713
}
@@ -27,5 +23,5 @@ final class MockPOSCatalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol {
2723
}
2824
}
2925

30-
func performIncrementalSyncIfApplicable(for siteID: Int64, forceSync: Bool) async throws {}
26+
func performIncrementalSyncIfApplicable(for siteID: Int64, maxAge: TimeInterval) async throws {}
3127
}

0 commit comments

Comments
 (0)