Skip to content

Commit eab9755

Browse files
Update code documentation
1 parent 0d761c9 commit eab9755

File tree

5 files changed

+137
-109
lines changed

5 files changed

+137
-109
lines changed

Sources/Implementation/DefaultDecisionService.swift

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,6 @@ struct VariationDecision {
2929
var cmabUUID: String?
3030
}
3131

32-
enum OperationType {
33-
case async
34-
case sync
35-
}
36-
37-
typealias OPType = OperationType
3832
typealias UserProfile = OPTUserProfileService.UPProfile
3933

4034
class DefaultDecisionService: OPTDecisionService {
@@ -44,14 +38,13 @@ class DefaultDecisionService: OPTDecisionService {
4438
let group: DispatchGroup = DispatchGroup()
4539
// thread-safe lazy logger load (after HandlerRegisterService ready)
4640
private let threadSafeLogger = ThreadSafeLogger()
47-
4841
// user-profile-service read-modify-write lock for supporting multiple clients
4942
static let upsRMWLock = DispatchQueue(label: "ups-rmw")
5043

5144
var logger: OPTLogger {
5245
return threadSafeLogger.logger
5346
}
54-
47+
5548
init(userProfileService: OPTUserProfileService,
5649
cmabService: CmabService = DefaultCmabService.createDefault()) {
5750
self.bucketer = DefaultBucketer()
@@ -74,24 +67,26 @@ class DefaultDecisionService: OPTDecisionService {
7467
/// - config: The project configuration containing experiment and feature details.
7568
/// - experiment: The CMAB experiment to evaluate.
7669
/// - user: The user context containing user ID and attributes.
70+
/// - bucketingId: User bucketing id
71+
/// - isAsync: Controls synchronous or asynchronous decision.
7772
/// - options: Optional decision options (e.g., ignore user profile service).
7873
/// - Returns: A `CMABDecisionResult` containing the CMAB decisions( variation id, cmabUUID) with reasons
7974

8075
private func getDecisionForCmabExperiment(config: ProjectConfig,
8176
experiment: Experiment,
8277
user: OptimizelyUserContext,
8378
bucketingId: String,
84-
opType: OPType,
79+
isAsync: Bool,
8580
options: [OptimizelyDecideOption]?) -> DecisionResponse<VariationDecision> {
8681
let reasons = DecisionReasons(options: options)
8782
guard let cmab = experiment.cmab else {
8883
logger.e("The experiment isn't a CMAB experiment")
8984
return DecisionResponse(result: nil, reasons: reasons)
9085
}
9186

92-
guard opType == .async else {
87+
guard isAsync else {
9388
let info = LogMessage.cmabNotSupportedInSyncMode
94-
logger.w(info)
89+
logger.e(info)
9590
reasons.addInfo(info)
9691
return DecisionResponse(result: nil, reasons: reasons)
9792
}
@@ -103,18 +98,18 @@ class DefaultDecisionService: OPTDecisionService {
10398
if let _reasons = bucketedResponse?.reasons {
10499
reasons.merge(_reasons)
105100
}
106-
101+
107102
let entityId = bucketedResponse?.result
108103

109-
// this means the user is not in the cmab experiment
104+
// This means the user is not in the cmab experiment
110105
if entityId == nil {
111106
let info = LogMessage.userNotInCmabExperiment(user.userId, experiment.key)
112107
logger.d(info)
113108
reasons.addInfo(info)
114109
return DecisionResponse(result: nil, reasons: reasons)
115110
}
116111

117-
/// Fetch CMAB decision
112+
// Fetch CMAB decision
118113
let response = cmabService.getDecision(config: config, userContext: user, ruleId: experiment.id, options: options ?? [])
119114
var cmabDecision: CmabDecision?
120115
switch response {
@@ -159,31 +154,14 @@ class DefaultDecisionService: OPTDecisionService {
159154
profileTracker?.loadUserProfile()
160155
}
161156

162-
let response = getVariation(config: config, experiment: experiment, user: user, userProfileTracker: profileTracker)
157+
// isAsync to `false` for backward compatibility
158+
let response = getVariation(config: config, experiment: experiment, user: user, isAsync: false, userProfileTracker: profileTracker)
163159

164160
if (!ignoreUPS) {
165161
profileTracker?.save()
166162
}
167163

168-
return response
169-
}
170-
171-
/// Determines the variation for a user in an experiment, considering user profile and decision rules.
172-
/// - Parameters:
173-
/// - config: The project configuration.
174-
/// - experiment: The experiment to evaluate.
175-
/// - user: The user context.
176-
/// - options: Optional decision options.
177-
/// - userProfileTracker: Optional tracker for user profile data.
178-
/// - Returns: A `DecisionResponse` with the variation (if any) and decision reasons.
179-
func getVariation(config: ProjectConfig,
180-
experiment: Experiment,
181-
user: OptimizelyUserContext,
182-
options: [OptimizelyDecideOption]? = nil,
183-
userProfileTracker: UserProfileTracker?) -> DecisionResponse<Variation> {
184-
let decisionResponse = self.getVariation(config: config, experiment: experiment, user: user, opType: .sync, userProfileTracker: userProfileTracker)
185-
186-
return DecisionResponse(result: decisionResponse.result?.variation, reasons: decisionResponse.reasons)
164+
return DecisionResponse(result: response.result?.variation, reasons: response.reasons)
187165
}
188166

189167
/// Determines the variation for a user in an experiment, considering user profile and decision rules.
@@ -192,14 +170,14 @@ class DefaultDecisionService: OPTDecisionService {
192170
/// - experiment: The experiment to evaluate.
193171
/// - user: The user context.
194172
/// - options: Optional decision options.
195-
/// - opType: Operation type, either sync or async
173+
/// - isAsync: Controls synchronous or asynchronous decision.
196174
/// - userProfileTracker: Optional tracker for user profile data.
197175
/// - Returns: A `DecisionResponse` with the variation (if any) and decision reasons.
198176
func getVariation(config: ProjectConfig,
199177
experiment: Experiment,
200178
user: OptimizelyUserContext,
201179
options: [OptimizelyDecideOption]? = nil,
202-
opType: OPType,
180+
isAsync: Bool,
203181
userProfileTracker: UserProfileTracker?) -> DecisionResponse<VariationDecision> {
204182
let reasons = DecisionReasons(options: options)
205183
let userId = user.userId
@@ -241,7 +219,7 @@ class DefaultDecisionService: OPTDecisionService {
241219
reasons.addInfo(info)
242220
}
243221

244-
/// Load variation from tracker
222+
// Load variation from tracker
245223
if let profile = userProfileTracker?.userProfile,
246224
let variationId = getVariationIdFromProfile(profile: profile, experimentId: experimentId),
247225
let variation = experiment.getVariation(id: variationId) {
@@ -270,12 +248,12 @@ class DefaultDecisionService: OPTDecisionService {
270248
experiment: experiment,
271249
user: user,
272250
bucketingId: bucketingId,
273-
opType: opType,
251+
isAsync: isAsync,
274252
options: options)
275253
reasons.merge(cmabDecisionResponse.reasons)
276254
variationDecision = cmabDecisionResponse.result
277255
} else {
278-
/// bucket user into a variation
256+
// bucket user into a variation
279257
let decisionResponse = bucketer.bucketExperiment(config: config,
280258
experiment: experiment,
281259
bucketingId: bucketingId)
@@ -318,17 +296,25 @@ class DefaultDecisionService: OPTDecisionService {
318296
featureFlag: FeatureFlag,
319297
user: OptimizelyUserContext,
320298
options: [OptimizelyDecideOption]? = nil) -> DecisionResponse<FeatureDecision> {
321-
322-
self.getVariationForFeature(config: config, featureFlag: featureFlag, user: user, opType: .sync, options: options)
299+
// isAsync to `false` for backward compatibility
300+
self.getVariationForFeature(config: config, featureFlag: featureFlag, user: user, isAsync: false, options: options)
323301
}
324302

303+
/// Determines the feature decision for a user for a specific feature flag.
304+
/// - Parameters:
305+
/// - config: The project configuration.
306+
/// - featureFlag: The feature flag to evaluate.
307+
/// - user: The user context.
308+
/// - isAsync: Controls synchronous or asynchronous decision.
309+
/// - options: Optional decision options.
310+
/// - Returns: A `DecisionResponse` with the feature decision (if any) and reasons.
325311
func getVariationForFeature(config: ProjectConfig,
326312
featureFlag: FeatureFlag,
327313
user: OptimizelyUserContext,
328-
opType: OPType,
314+
isAsync: Bool,
329315
options: [OptimizelyDecideOption]? = nil) -> DecisionResponse<FeatureDecision> {
330316

331-
let response = getVariationForFeatureList(config: config, featureFlags: [featureFlag], user: user, opType: opType, options: options).first
317+
let response = getVariationForFeatureList(config: config, featureFlags: [featureFlag], user: user, isAsync: isAsync, options: options).first
332318

333319
guard response?.result != nil else {
334320
let reasons = response?.reasons ?? DecisionReasons(options: options)
@@ -343,12 +329,13 @@ class DefaultDecisionService: OPTDecisionService {
343329
/// - config: The project configuration.
344330
/// - featureFlags: The list of feature flags to evaluate.
345331
/// - user: The user context.
332+
/// - isAsync: Controls synchronous or asynchronous decision
346333
/// - options: Optional decision options.
347334
/// - Returns: An array of `DecisionResponse` objects, each containing a feature decision and reasons.
348335
func getVariationForFeatureList(config: ProjectConfig,
349336
featureFlags: [FeatureFlag],
350337
user: OptimizelyUserContext,
351-
opType: OPType = .sync,
338+
isAsync: Bool,
352339
options: [OptimizelyDecideOption]? = nil) -> [DecisionResponse<FeatureDecision>] {
353340

354341
let userId = user.userId
@@ -362,7 +349,7 @@ class DefaultDecisionService: OPTDecisionService {
362349
var decisions = [DecisionResponse<FeatureDecision>]()
363350

364351
for featureFlag in featureFlags {
365-
let flagDecisionResponse = getDecisionForFlag(config: config, featureFlag: featureFlag, user: user, userProfileTracker: profileTracker, opType: opType, options: options)
352+
let flagDecisionResponse = getDecisionForFlag(config: config, featureFlag: featureFlag, user: user, userProfileTracker: profileTracker, isAsync: isAsync, options: options)
366353
decisions.append(flagDecisionResponse)
367354
}
368355

@@ -380,13 +367,14 @@ class DefaultDecisionService: OPTDecisionService {
380367
/// - featureFlag: The feature flag to evaluate.
381368
/// - user: The user context.
382369
/// - userProfileTracker: Optional tracker for user profile data.
370+
/// - isAsync: Controls synchronous or asynchronous decision
383371
/// - options: Optional decision options.
384372
/// - Returns: A `DecisionResponse` with the feature decision (if any) and reasons.
385373
func getDecisionForFlag(config: ProjectConfig,
386374
featureFlag: FeatureFlag,
387375
user: OptimizelyUserContext,
388376
userProfileTracker: UserProfileTracker? = nil,
389-
opType: OPType,
377+
isAsync: Bool,
390378
options: [OptimizelyDecideOption]? = nil) -> DecisionResponse<FeatureDecision> {
391379
let reasons = DecisionReasons(options: options)
392380

@@ -404,7 +392,7 @@ class DefaultDecisionService: OPTDecisionService {
404392
}
405393
}
406394

407-
let flagExpDecision = getVariationForFeatureExperiments(config: config, featureFlag: featureFlag, user: user, userProfileTracker: userProfileTracker, opType: opType, options: options)
395+
let flagExpDecision = getVariationForFeatureExperiments(config: config, featureFlag: featureFlag, user: user, userProfileTracker: userProfileTracker, isAsync: isAsync, options: options)
408396
reasons.merge(flagExpDecision.reasons)
409397

410398
if let decision = flagExpDecision.result {
@@ -427,13 +415,14 @@ class DefaultDecisionService: OPTDecisionService {
427415
/// - featureFlag: The feature flag to evaluate.
428416
/// - user: The user context.
429417
/// - userProfileTracker: Optional tracker for user profile data.
418+
/// - isAsync: Controls synchronous or asynchronous decision
430419
/// - options: Optional decision options.
431420
/// - Returns: A `DecisionResponse` with the feature decision (if any) and reasons.
432421
func getVariationForFeatureExperiments(config: ProjectConfig,
433422
featureFlag: FeatureFlag,
434423
user: OptimizelyUserContext,
435424
userProfileTracker: UserProfileTracker? = nil,
436-
opType: OPType = .sync,
425+
isAsync: Bool,
437426
options: [OptimizelyDecideOption]? = nil) -> DecisionResponse<FeatureDecision> {
438427
let reasons = DecisionReasons(options: options)
439428

@@ -453,7 +442,7 @@ class DefaultDecisionService: OPTDecisionService {
453442
rule: experiment,
454443
user: user,
455444
userProfileTracker: userProfileTracker,
456-
opType: opType,
445+
isAsync: isAsync,
457446
options: options)
458447
reasons.merge(decisionResponse.reasons)
459448
if let result = decisionResponse.result {
@@ -563,7 +552,7 @@ class DefaultDecisionService: OPTDecisionService {
563552

564553
let userId = user.userId
565554
let attributes = user.attributes
566-
555+
567556
// Acquire bucketingId .
568557
let bucketingId = getBucketingId(userId: userId, attributes: attributes)
569558
var bucketedVariation: Variation?
@@ -614,7 +603,7 @@ class DefaultDecisionService: OPTDecisionService {
614603
rule: Experiment,
615604
user: OptimizelyUserContext,
616605
userProfileTracker: UserProfileTracker?,
617-
opType: OPType = .sync,
606+
isAsync: Bool,
618607
options: [OptimizelyDecideOption]? = nil) -> DecisionResponse<VariationDecision> {
619608
let reasons = DecisionReasons(options: options)
620609
// check forced-decision first
@@ -632,7 +621,7 @@ class DefaultDecisionService: OPTDecisionService {
632621
experiment: rule,
633622
user: user,
634623
options: options,
635-
opType: opType,
624+
isAsync: isAsync,
636625
userProfileTracker: userProfileTracker)
637626
let variationResult = decisionResponse.result
638627
reasons.merge(decisionResponse.reasons)
@@ -656,7 +645,7 @@ class DefaultDecisionService: OPTDecisionService {
656645
options: [OptimizelyDecideOption]? = nil) -> DecisionResponse<(Variation?, Bool)> {
657646
let reasons = DecisionReasons(options: options)
658647
var skipToEveryoneElse = false
659-
648+
660649
// check forced-decision first
661650

662651
let rule = rules[ruleIndex]

0 commit comments

Comments
 (0)