Skip to content

Commit 799ab5d

Browse files
refactor: improve thread safety in getDecision function
- Introduce a lock array to prevent race conditions - Implement getLockIndex method for calculating lock index based on user and rule IDs
1 parent 5f38cf5 commit 799ab5d

File tree

1 file changed

+26
-9
lines changed

1 file changed

+26
-9
lines changed

Sources/CMAB/CmabService.swift

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,42 @@ class DefaultCmabService: CmabService {
4848
private let cmabCache: LruCache<String, CmabCacheValue>
4949
private let logger = OPTLoggerFactory.getLogger()
5050

51+
private static let NUM_LOCKS = 1000
52+
private let locks: [NSLock]
53+
5154
init(cmabClient: CmabClient, cmabCache: LruCache<String, CmabCacheValue>) {
5255
self.cmabClient = cmabClient
5356
self.cmabCache = cmabCache
57+
self.locks = (0..<Self.NUM_LOCKS).map { _ in NSLock() }
58+
}
59+
60+
private func getLockIndex(userId: String, ruleId: String) -> Int {
61+
let combinedKey = userId + ruleId
62+
let hashValue = combinedKey.hashValue
63+
// Take absolute value to ensure positive number
64+
let positiveHash = abs(hashValue)
65+
// Use modulo to map to lock array index [0, NUM_LOCKS-1]
66+
return positiveHash % Self.NUM_LOCKS
5467
}
5568

5669
func getDecision(config: ProjectConfig,
5770
userContext: OptimizelyUserContext,
5871
ruleId: String,
5972
options: [OptimizelyDecideOption]) -> Result<CmabDecision, Error> {
60-
var result: Result<CmabDecision, Error>!
61-
let semaphore = DispatchSemaphore(value: 0)
62-
getDecision(config: config,
63-
userContext: userContext,
64-
ruleId: ruleId, options: options) { _result in
65-
result = _result
66-
semaphore.signal()
73+
let lockIdx = getLockIndex(userId: userContext.userId, ruleId: ruleId)
74+
let lock = locks[lockIdx]
75+
return lock.withLock {
76+
var result: Result<CmabDecision, Error>!
77+
let semaphore = DispatchSemaphore(value: 0)
78+
getDecision(config: config,
79+
userContext: userContext,
80+
ruleId: ruleId, options: options) { _result in
81+
result = _result
82+
semaphore.signal()
83+
}
84+
semaphore.wait()
85+
return result
6786
}
68-
semaphore.wait()
69-
return result
7087
}
7188

7289
func getDecision(config: ProjectConfig,

0 commit comments

Comments
 (0)