Skip to content
This repository has been archived by the owner on Nov 9, 2022. It is now read-only.

Commit

Permalink
Try to prevent race condition when writing and reading tasks cache by…
Browse files Browse the repository at this point in the history
… using dedicated sync thread
  • Loading branch information
Ondřej Korol committed Jun 28, 2021
1 parent 90f44f2 commit 87b6098
Showing 1 changed file with 43 additions and 6 deletions.
49 changes: 43 additions & 6 deletions ChatCore/Utils/TaskManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,42 @@ import BackgroundTasks

// MARK: Helper class to automatically manage closures by applying various attributes
final class TaskManager {
class TaskCache {
private var storage: [IdentifiableClosure<TaskCompletionResultHandler, Void>: Set<TaskAttribute>] = [:]
private let queue = DispatchQueue(label: "com.strv.chatcore.taskcache.queue")

public subscript(key: IdentifiableClosure<TaskCompletionResultHandler, Void>) -> Set<TaskAttribute> {
get {
return queue.sync {
return storage[key] ?? []
}
}
set {
queue.sync {
storage[key] = newValue
}
}
}

public var isEmpty: Bool {
return queue.sync {
return storage.isEmpty
}
}

public var allTasks: [IdentifiableClosure<TaskCompletionResultHandler, Void>: Set<TaskAttribute>] {
return queue.sync {
return storage
}
}

public func removeAll() {
return queue.sync {
return storage.removeAll()
}
}
}

enum RetryType {
case finite(attempts: Int = 3)
case infinite
Expand Down Expand Up @@ -54,8 +90,8 @@ final class TaskManager {
// Validate state of task after result on internal call
typealias TaskCompletionResultHandler = (TaskCompletionResult) -> TaskCompletionState

// closure storage for calls before init
private var cachedBeforeInitCalls: [IdentifiableClosure<TaskCompletionResultHandler, Void>: Set<TaskAttribute>] = [:]
// Closure storage for calls before initialization
private let taskCache = TaskCache()
// tasks hooked to background task
private var backgroundCalls = [IdentifiableClosure<TaskCompletionResultHandler, Void>]()
private var backgroundTask: UIBackgroundTaskIdentifier = .invalid
Expand Down Expand Up @@ -196,21 +232,22 @@ private extension TaskManager {
func applyAfterInit(_ identifiableClosure: IdentifiableClosure<TaskCompletionResultHandler, Void>, attributes: Set<TaskAttribute>) {
logger.log("Hook after init task id \(identifiableClosure.id)", level: .debug)
guard initialized else {
cachedBeforeInitCalls[identifiableClosure] = attributes
taskCache[identifiableClosure] = attributes
// to alow chaining
return
}
}

func runCachedTasks() {
guard !cachedBeforeInitCalls.isEmpty else {
guard !taskCache.isEmpty else {
return
}

cachedBeforeInitCalls.forEach { (key, value) in
taskCache.allTasks.forEach { (key, value) in
run(attributes: value, key)
}
cachedBeforeInitCalls.removeAll()

taskCache.removeAll()
}
}

Expand Down

0 comments on commit 87b6098

Please sign in to comment.