statsig 2.4.3 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/evaluator.rb +52 -3
- data/lib/memo.rb +5 -1
- data/lib/statsig.rb +21 -1
- data/lib/statsig_driver.rb +14 -4
- data/lib/statsig_event.rb +1 -2
- data/lib/statsig_options.rb +7 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d4842b01ba9c40089bbf689984a0c9a59234d83f0d070c2570856335ad012fc
|
4
|
+
data.tar.gz: 44afa2a46886c397ecc2975f123d9808f08548fadd7e9703130cd6099033d159
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13ec911e8fb874d705ace7bc92d857dfa8a71171812b822f2af2826e9f52af01d03af8661bfd42866d7c7560b5a050a9ff2e936084eb61d18a46c67555bf5ea7
|
7
|
+
data.tar.gz: 61c0be14ffc93a7bc0db3fe25932a09e8dab52fdb7eaf50b2e15ffef44cba975ddf5706b328ba8f9e0eef6ef0b744856b691efbfae72c247fb58a0d04465a86e
|
data/lib/evaluator.rb
CHANGED
@@ -20,6 +20,8 @@ module Statsig
|
|
20
20
|
|
21
21
|
attr_accessor :config_overrides
|
22
22
|
|
23
|
+
attr_accessor :experiment_overrides
|
24
|
+
|
23
25
|
attr_accessor :options
|
24
26
|
|
25
27
|
attr_accessor :persistent_storage_utils
|
@@ -31,6 +33,7 @@ module Statsig
|
|
31
33
|
@spec_store = store
|
32
34
|
@gate_overrides = {}
|
33
35
|
@config_overrides = {}
|
36
|
+
@experiment_overrides = {}
|
34
37
|
@options = options
|
35
38
|
@persistent_storage_utils = persistent_storage_utils
|
36
39
|
end
|
@@ -58,19 +61,32 @@ module Statsig
|
|
58
61
|
|
59
62
|
def lookup_config_override(config_name)
|
60
63
|
config_name_sym = config_name.to_sym
|
64
|
+
if @experiment_overrides.key?(config_name_sym)
|
65
|
+
override = @experiment_overrides[config_name_sym]
|
66
|
+
return ConfigResult.new(
|
67
|
+
name: config_name,
|
68
|
+
json_value: override[:value],
|
69
|
+
group_name: override[:group_name],
|
70
|
+
rule_id: override[:rule_id],
|
71
|
+
evaluation_details: EvaluationDetails.local_override(
|
72
|
+
@spec_store.last_config_sync_time,
|
73
|
+
@spec_store.initial_config_sync_time
|
74
|
+
)
|
75
|
+
)
|
76
|
+
end
|
61
77
|
if @config_overrides.key?(config_name_sym)
|
78
|
+
override = @config_overrides[config_name_sym]
|
62
79
|
return ConfigResult.new(
|
63
80
|
name: config_name,
|
64
|
-
json_value:
|
81
|
+
json_value: override,
|
65
82
|
rule_id: Const::OVERRIDE,
|
66
|
-
id_type: @spec_store.has_config?(config_name) ? @spec_store.get_config(config_name)[:idType] : Const::EMPTY_STR,
|
67
83
|
evaluation_details: EvaluationDetails.local_override(
|
68
84
|
@spec_store.last_config_sync_time,
|
69
85
|
@spec_store.initial_config_sync_time
|
70
86
|
)
|
71
87
|
)
|
72
88
|
end
|
73
|
-
|
89
|
+
nil
|
74
90
|
end
|
75
91
|
|
76
92
|
def check_gate(user, gate_name, end_result, ignore_local_overrides: false, is_nested: false)
|
@@ -108,6 +124,8 @@ module Statsig
|
|
108
124
|
end_result.id_type = local_override.id_type
|
109
125
|
end_result.rule_id = local_override.rule_id
|
110
126
|
end_result.json_value = local_override.json_value
|
127
|
+
end_result.group_name = local_override.group_name
|
128
|
+
end_result.is_experiment_group = local_override.is_experiment_group
|
111
129
|
unless end_result.disable_evaluation_details
|
112
130
|
end_result.evaluation_details = local_override.evaluation_details
|
113
131
|
end
|
@@ -447,6 +465,37 @@ module Statsig
|
|
447
465
|
@config_overrides.clear
|
448
466
|
end
|
449
467
|
|
468
|
+
def override_experiment_by_group_name(experiment_name, group_name)
|
469
|
+
return unless @spec_store.has_config?(experiment_name)
|
470
|
+
|
471
|
+
config = @spec_store.get_config(experiment_name)
|
472
|
+
return unless config[:entity] == Const::TYPE_EXPERIMENT
|
473
|
+
|
474
|
+
config[:rules].each do |rule|
|
475
|
+
if rule[:groupName] == group_name
|
476
|
+
@experiment_overrides[experiment_name.to_sym] = {
|
477
|
+
value: rule[:returnValue],
|
478
|
+
group_name: rule[:groupName],
|
479
|
+
rule_id: rule[:id],
|
480
|
+
evaluation_details: EvaluationDetails.local_override(@config_sync_time, @init_time)
|
481
|
+
}
|
482
|
+
return
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
# If no matching rule is found, create a default override with empty value
|
487
|
+
@experiment_overrides[experiment_name.to_sym] = {
|
488
|
+
value: {},
|
489
|
+
group_name: group_name,
|
490
|
+
rule_id: "#{experiment_name}:override",
|
491
|
+
evaluation_details: EvaluationDetails.local_override(@config_sync_time, @init_time)
|
492
|
+
}
|
493
|
+
end
|
494
|
+
|
495
|
+
def clear_experiment_overrides
|
496
|
+
@experiment_overrides.clear
|
497
|
+
end
|
498
|
+
|
450
499
|
def eval_spec(config_name, user, config, end_result, is_nested: false)
|
451
500
|
config[:rules].each do |rule|
|
452
501
|
end_result.sampling_rate = rule[:samplingRate]
|
data/lib/memo.rb
CHANGED
@@ -3,7 +3,11 @@ module Statsig
|
|
3
3
|
|
4
4
|
@global_memo = {}
|
5
5
|
|
6
|
-
def self.for(hash, method, key)
|
6
|
+
def self.for(hash, method, key, disable_evaluation_memoization: false)
|
7
|
+
if disable_evaluation_memoization
|
8
|
+
return yield
|
9
|
+
end
|
10
|
+
|
7
11
|
if key != nil
|
8
12
|
method_hash = hash[method]
|
9
13
|
unless method_hash
|
data/lib/statsig.rb
CHANGED
@@ -328,6 +328,17 @@ module Statsig
|
|
328
328
|
@shared_instance&.override_config(config_name, config_value)
|
329
329
|
end
|
330
330
|
|
331
|
+
|
332
|
+
##
|
333
|
+
# Overrides an experiment to return the value for a specific group name.
|
334
|
+
#
|
335
|
+
# @param experiment_name The name of the experiment to be overridden
|
336
|
+
# @param group_name The name of the group whose value should be returned
|
337
|
+
def self.override_experiment_by_group_name(experiment_name, group_name)
|
338
|
+
ensure_initialized
|
339
|
+
@shared_instance&.override_experiment_by_group_name(experiment_name, group_name)
|
340
|
+
end
|
341
|
+
|
331
342
|
def self.remove_config_override(config_name)
|
332
343
|
ensure_initialized
|
333
344
|
@shared_instance&.remove_config_override(config_name)
|
@@ -338,6 +349,11 @@ module Statsig
|
|
338
349
|
@shared_instance&.clear_config_overrides
|
339
350
|
end
|
340
351
|
|
352
|
+
def self.clear_experiment_overrides
|
353
|
+
ensure_initialized
|
354
|
+
@shared_instance&.clear_experiment_overrides
|
355
|
+
end
|
356
|
+
|
341
357
|
##
|
342
358
|
# @param [HashTable] debug information log with exposure events
|
343
359
|
def self.set_debug_info(debug_info)
|
@@ -370,11 +386,15 @@ module Statsig
|
|
370
386
|
def self.get_statsig_metadata
|
371
387
|
{
|
372
388
|
'sdkType' => 'ruby-server',
|
373
|
-
'sdkVersion' => '2.
|
389
|
+
'sdkVersion' => '2.5.0',
|
374
390
|
'languageVersion' => RUBY_VERSION
|
375
391
|
}
|
376
392
|
end
|
377
393
|
|
394
|
+
def self.get_options
|
395
|
+
@driver&.instance_variable_get(:@options)
|
396
|
+
end
|
397
|
+
|
378
398
|
private
|
379
399
|
|
380
400
|
def self.ensure_initialized
|
data/lib/statsig_driver.rb
CHANGED
@@ -65,7 +65,7 @@ class StatsigDriver
|
|
65
65
|
|
66
66
|
user = verify_inputs(user, gate_name, 'gate_name')
|
67
67
|
|
68
|
-
Statsig::Memo.for(user.get_memo, :get_gate_impl, gate_name) do
|
68
|
+
Statsig::Memo.for(user.get_memo, :get_gate_impl, gate_name, disable_evaluation_memoization: @options.disable_evaluation_memoization) do
|
69
69
|
res = Statsig::ConfigResult.new(
|
70
70
|
name: gate_name,
|
71
71
|
disable_exposures: disable_log_exposure,
|
@@ -171,7 +171,7 @@ class StatsigDriver
|
|
171
171
|
@err_boundary.capture(caller: __method__, recover: -> { Layer.new(layer_name) }) do
|
172
172
|
run_with_diagnostics(caller: :get_layer) do
|
173
173
|
user = verify_inputs(user, layer_name, "layer_name")
|
174
|
-
Statsig::Memo.for(user.get_memo, :get_layer, layer_name) do
|
174
|
+
Statsig::Memo.for(user.get_memo, :get_layer, layer_name, disable_evaluation_memoization: @options.disable_evaluation_memoization) do
|
175
175
|
exposures_disabled = options&.disable_log_exposure == true
|
176
176
|
res = Statsig::ConfigResult.new(
|
177
177
|
name: layer_name,
|
@@ -304,6 +304,12 @@ class StatsigDriver
|
|
304
304
|
end
|
305
305
|
end
|
306
306
|
|
307
|
+
def clear_experiment_overrides
|
308
|
+
@err_boundary.capture(caller: __method__) do
|
309
|
+
@evaluator.clear_experiment_overrides
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
307
313
|
def set_debug_info(debug_info)
|
308
314
|
@err_boundary.capture(caller: __method__) do
|
309
315
|
@logger.set_debug_info(debug_info)
|
@@ -337,6 +343,10 @@ class StatsigDriver
|
|
337
343
|
end
|
338
344
|
end
|
339
345
|
|
346
|
+
def override_experiment_by_group_name(experiment_name, group_name)
|
347
|
+
@evaluator.override_experiment_by_group_name(experiment_name, group_name)
|
348
|
+
end
|
349
|
+
|
340
350
|
private
|
341
351
|
|
342
352
|
def run_with_diagnostics(caller:)
|
@@ -361,7 +371,7 @@ class StatsigDriver
|
|
361
371
|
|
362
372
|
def verify_inputs(user, config_name, variable_name)
|
363
373
|
validate_user(user)
|
364
|
-
user = Statsig::Memo.for(user.get_memo(), :verify_inputs, 0) do
|
374
|
+
user = Statsig::Memo.for(user.get_memo(), :verify_inputs, 0, disable_evaluation_memoization: @options.disable_evaluation_memoization) do
|
365
375
|
user = normalize_user(user)
|
366
376
|
check_shutdown
|
367
377
|
maybe_restart_background_threads
|
@@ -376,7 +386,7 @@ class StatsigDriver
|
|
376
386
|
end
|
377
387
|
|
378
388
|
def get_config_impl(user, config_name, disable_log_exposure, user_persisted_values: nil, disable_evaluation_details: false, ignore_local_overrides: false)
|
379
|
-
Statsig::Memo.for(user.get_memo, :get_config_impl, config_name) do
|
389
|
+
Statsig::Memo.for(user.get_memo, :get_config_impl, config_name, disable_evaluation_memoization: @options.disable_evaluation_memoization) do
|
380
390
|
res = Statsig::ConfigResult.new(
|
381
391
|
name: config_name,
|
382
392
|
disable_exposures: disable_log_exposure,
|
data/lib/statsig_event.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
class StatsigEvent
|
3
2
|
attr_accessor :value, :metadata, :statsig_metadata, :secondary_exposures
|
4
3
|
attr_reader :user
|
@@ -15,7 +14,7 @@ class StatsigEvent
|
|
15
14
|
|
16
15
|
def user=(value)
|
17
16
|
if value.is_a?(StatsigUser)
|
18
|
-
@user = Statsig::Memo.for(value.get_memo(), :serialize, 0) do
|
17
|
+
@user = Statsig::Memo.for(value.get_memo(), :serialize, 0, disable_evaluation_memoization: Statsig.get_options&.disable_evaluation_memoization) do
|
19
18
|
value.serialize(true)
|
20
19
|
end
|
21
20
|
end
|
data/lib/statsig_options.rb
CHANGED
@@ -88,6 +88,10 @@ class StatsigOptions
|
|
88
88
|
# Implements Statsig::Interfaces::IUserPersistentStorage.
|
89
89
|
attr_accessor :user_persistent_storage
|
90
90
|
|
91
|
+
# Disable memoization of evaluation results. When true, each evaluation will be performed fresh.
|
92
|
+
# default: false
|
93
|
+
attr_accessor :disable_evaluation_memoization
|
94
|
+
|
91
95
|
def initialize(
|
92
96
|
environment = nil,
|
93
97
|
download_config_specs_url: nil,
|
@@ -110,7 +114,8 @@ class StatsigOptions
|
|
110
114
|
network_timeout: nil,
|
111
115
|
post_logs_retry_limit: 3,
|
112
116
|
post_logs_retry_backoff: nil,
|
113
|
-
user_persistent_storage: nil
|
117
|
+
user_persistent_storage: nil,
|
118
|
+
disable_evaluation_memoization: false
|
114
119
|
)
|
115
120
|
@environment = environment.is_a?(Hash) ? environment : nil
|
116
121
|
|
@@ -140,6 +145,6 @@ class StatsigOptions
|
|
140
145
|
@post_logs_retry_limit = post_logs_retry_limit
|
141
146
|
@post_logs_retry_backoff = post_logs_retry_backoff
|
142
147
|
@user_persistent_storage = user_persistent_storage
|
143
|
-
|
148
|
+
@disable_evaluation_memoization = disable_evaluation_memoization
|
144
149
|
end
|
145
150
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statsig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Statsig, Inc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-05-
|
11
|
+
date: 2025-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|