Fix nasty bug !

sync2
Laurent 8 months ago
parent b151fe8674
commit 6d8ce05dae
  1. 35
      LeStorage/ApiCallCollection.swift
  2. 10
      LeStorage/Services.swift
  3. 4
      LeStorage/StoreCenter.swift
  4. 13
      LeStorage/StoredCollection+Sync.swift

@ -46,7 +46,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
fileprivate var _attemptLoops: Int = 0
/// Indicates if the collection is currently retrying ApiCalls
fileprivate var _isRescheduling: Bool = false
fileprivate var _isExecutingCalls: Bool = false
fileprivate var _schedulingTask: Task<(), Never>? = nil
@ -140,7 +140,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
/// Removes all objects in memory and deletes the JSON file
func reset() {
self._isRescheduling = false
self._isExecutingCalls = false
self.items.removeAll()
do {
@ -157,11 +157,11 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
self._attemptLoops = -1
self.rescheduleApiCallsIfNecessary()
// if self._schedulingTask != nil && self._attemptLoops > 2 {
// self._schedulingTask?.cancel()
// self._attemptLoops = -1
// self.rescheduleApiCallsIfNecessary()
// }
if self._schedulingTask != nil && self._attemptLoops > 2 {
self._schedulingTask?.cancel()
self._attemptLoops = -1
self.rescheduleApiCallsIfNecessary()
}
}
func rescheduleImmediately() {
@ -171,7 +171,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
/// Reschedule API calls if necessary
func rescheduleApiCallsIfNecessary() {
if self.items.isNotEmpty && !self._isRescheduling {
if self.items.isNotEmpty && !self._isExecutingCalls {
self._schedulingTask = Task {
await self._waitAndExecuteApiCalls()
}
@ -182,15 +182,16 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
fileprivate func _waitAndExecuteApiCalls() async {
// Logger.log("\(T.resourceName()) > RESCHED")
guard !self._isRescheduling, StoreCenter.main.collectionsCanSynchronize else { return }
guard !self._isExecutingCalls, StoreCenter.main.collectionsCanSynchronize else { return }
guard self.items.isNotEmpty else { return }
self._isRescheduling = true
self._isExecutingCalls = true
self._attemptLoops += 1
await self._wait()
// Logger.log("\(T.resourceName()) > EXECUTE CALLS: \(self.items.count)")
let batches = Dictionary(grouping: self.items, by: { $0.transactionId })
for batch in batches.values {
@ -209,7 +210,8 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
}
}
self._isRescheduling = false
// Logger.log("\(T.resourceName()) > EXECUTE CALLS ENDED !")
self._isExecutingCalls = false
if self.items.isNotEmpty {
await self._waitAndExecuteApiCalls()
}
@ -229,6 +231,8 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
/// Wait for an exponentionnaly long time depending on the number of attemps
fileprivate func _wait() async {
guard self._attemptLoops > 0 else { return }
var seconds = self._attemptLoops
if self._attemptLoops > 5 {
let delay = pow(2, self._attemptLoops - 2) // starts at 16s
@ -313,7 +317,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
}
}
func executeBatch(_ batch: OperationBatch<T>) async throws -> [OperationResult<T>] {
func executeBatch(_ batch: OperationBatch<T>) async throws {
var apiCalls: [ApiCall<T>] = []
let transactionId = Store.randomId()
@ -329,7 +333,9 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
let call = try self.callForInstance(delete, method: .delete, transactionId: transactionId)
apiCalls.append(call)
}
return try await self._executeApiCalls(apiCalls)
self.rescheduleApiCallsIfNecessary()
// return try await self._executeApiCalls(apiCalls)
}
fileprivate func _prepareAndSendGetCall(_ apiCall: ApiCall<T>) async throws {
@ -346,6 +352,9 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
/// Executes an API call
/// For POST requests, potentially copies additional data coming from the server during the insert
fileprivate func _executeApiCalls(_ apiCalls: [ApiCall<T>]) async throws -> [OperationResult<T>] {
// for call in apiCalls {
// Logger.log("execute call = \(call.id)")
// }
let results = try await StoreCenter.main.execute(apiCalls: apiCalls)
for result in results {
switch result.status {

@ -308,7 +308,7 @@ public class Services {
if let response = task.1 as? HTTPURLResponse {
let statusCode = response.statusCode
print("\(debugURL) ended, status code = \(statusCode)")
print("\(String(describing: T.self))> \(debugURL) ended, status code = \(statusCode)")
switch statusCode {
case 200..<300: // success
@ -320,14 +320,10 @@ public class Services {
switch result.status {
case 200..<300:
break
// if let data = result.data {
// successes.append(data)
// }
// try await StoreCenter.main.deleteApiCallById(type: T.self, id: result.apiCallId)
default:
if let message = result.message {
print(message)
let type = String(describing: T.self)
print("\(type) - \(result.apiCallId): \(result.status) > \(message)")
}
rescheduleApiCalls = true
break

@ -403,9 +403,9 @@ public class StoreCenter {
&& self.userIsAllowed()
}
func sendOperationBatch<T: SyncedStorable>(_ batch: OperationBatch<T>) async throws -> [OperationResult<T>] {
func sendOperationBatch<T: SyncedStorable>(_ batch: OperationBatch<T>) async throws {
guard self._canSynchronise() else {
return []
return
}
return try await self.apiCallCollection().executeBatch(batch)
}

@ -218,12 +218,13 @@ extension StoredCollection: SomeSyncedCollection where T : SyncedStorable {
fileprivate func _sendOperationBatch(_ batch: OperationBatch<T>) {
Task {
do {
let success = try await StoreCenter.main.sendOperationBatch(batch)
for item in success {
if let data = item.data {
self.updateFromServerInstance(data)
}
}
try await StoreCenter.main.sendOperationBatch(batch)
// let success = try await StoreCenter.main.sendOperationBatch(batch)
// for item in success {
// if let data = item.data {
// self.updateFromServerInstance(data)
// }
// }
} catch {
Logger.error(error)
}

Loading…
Cancel
Save