-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement shedding identity queue
Previously, customers could queue a boundless limit of identify requests. The SDK would work its way through this FIFO queue, processing all intermediate but unnecessary requests. With this change, intermediate identify requests will be shed from the processing queue. NOTE: To preserve backwards compatibility, the original identify method will queue up "unsheddable" tasks which will continue to queue as before. Usage of the new `identify` method will allow developers to opt-in to this new behavior.
- Loading branch information
Showing
5 changed files
with
356 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import Foundation | ||
|
||
/** | ||
Denotes the result of an identify request made through the `LDClient.identify(context: completion:)` method. | ||
*/ | ||
public enum IdentifyResult { | ||
/** | ||
The identify request has completed successfully. | ||
*/ | ||
case complete | ||
/** | ||
The identify request has received an unrecoverable failure. | ||
*/ | ||
case error | ||
/** | ||
The identify request has been replaced with a subsequent request. See `LDClient.identify(context: completion:)` for more details. | ||
*/ | ||
case shed | ||
|
||
init(from: TaskResult) { | ||
switch from { | ||
case .complete: | ||
self = .complete | ||
case .error: | ||
self = .error | ||
case .shed: | ||
self = .shed | ||
} | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
LaunchDarkly/LaunchDarkly/ServiceObjects/SheddingQueue.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import Foundation | ||
|
||
enum TaskResult { | ||
case complete | ||
case error | ||
case shed | ||
} | ||
|
||
typealias TaskHandlerCompletion = () -> Void | ||
typealias TaskHandler = (_ completion: @escaping TaskHandlerCompletion) -> Void | ||
typealias TaskCompletion = (_ result: TaskResult) -> Void | ||
|
||
struct Task { | ||
let work: TaskHandler | ||
let sheddable: Bool | ||
let completion: TaskCompletion | ||
} | ||
|
||
class SheddingQueue { | ||
private let stateQueue: DispatchQueue = DispatchQueue(label: "StateQueue") | ||
private let identifyQueue: DispatchQueue = DispatchQueue(label: "IdentifyQueue") | ||
|
||
private var inFlight: Task? | ||
private var queue: [Task] = [] | ||
|
||
func enqueue(request: Task) { | ||
stateQueue.async { [self] in | ||
guard inFlight != nil else { | ||
inFlight = request | ||
identifyQueue.async { self.execute() } | ||
return | ||
} | ||
|
||
if let lastTask = queue.last, lastTask.sheddable { | ||
queue.removeLast() | ||
lastTask.completion(.shed) | ||
} | ||
|
||
queue.append(request) | ||
} | ||
} | ||
|
||
private func execute() { | ||
var nextTask: Task? | ||
|
||
stateQueue.sync { | ||
nextTask = inFlight | ||
} | ||
|
||
if nextTask == nil { | ||
return | ||
} | ||
|
||
guard let request = nextTask else { return } | ||
|
||
request.work() { [self] in | ||
request.completion(.complete) | ||
|
||
stateQueue.sync { | ||
inFlight = queue.first | ||
if inFlight != nil { | ||
queue.remove(at: 0) | ||
identifyQueue.async { self.execute() } | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.