statsig 1.31.1 → 1.32.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/api_config.rb +128 -0
- data/lib/client_initialize_helpers.rb +78 -88
- data/lib/config_result.rb +17 -32
- data/lib/constants.rb +60 -0
- data/lib/diagnostics.rb +1 -38
- data/lib/dynamic_config.rb +1 -24
- data/lib/error_boundary.rb +0 -5
- data/lib/evaluation_details.rb +4 -1
- data/lib/evaluation_helpers.rb +35 -3
- data/lib/evaluator.rb +332 -327
- data/lib/feature_gate.rb +0 -24
- data/lib/id_list.rb +1 -1
- data/lib/interfaces/data_store.rb +1 -1
- data/lib/interfaces/user_persistent_storage.rb +1 -1
- data/lib/layer.rb +1 -20
- data/lib/network.rb +6 -33
- data/lib/spec_store.rb +86 -74
- data/lib/statsig.rb +72 -97
- data/lib/statsig_driver.rb +63 -70
- data/lib/statsig_errors.rb +1 -1
- data/lib/statsig_event.rb +8 -8
- data/lib/statsig_logger.rb +21 -21
- data/lib/statsig_options.rb +0 -50
- data/lib/statsig_user.rb +27 -68
- data/lib/ua_parser.rb +1 -1
- data/lib/uri_helper.rb +1 -9
- data/lib/user_persistent_storage_utils.rb +0 -17
- metadata +8 -6
data/lib/feature_gate.rb
CHANGED
@@ -1,42 +1,19 @@
|
|
1
|
-
# typed: false
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
|
-
|
5
1
|
class FeatureGate
|
6
|
-
extend T::Sig
|
7
2
|
|
8
|
-
sig { returns(String) }
|
9
3
|
attr_accessor :name
|
10
4
|
|
11
|
-
sig { returns(T::Boolean) }
|
12
5
|
attr_accessor :value
|
13
6
|
|
14
|
-
sig { returns(String) }
|
15
7
|
attr_accessor :rule_id
|
16
8
|
|
17
|
-
sig { returns(T.nilable(String)) }
|
18
9
|
attr_accessor :group_name
|
19
10
|
|
20
|
-
sig { returns(String) }
|
21
11
|
attr_accessor :id_type
|
22
12
|
|
23
|
-
sig { returns(T.nilable(Statsig::EvaluationDetails)) }
|
24
13
|
attr_accessor :evaluation_details
|
25
14
|
|
26
|
-
sig { returns(T.nilable(T::Array[String])) }
|
27
15
|
attr_accessor :target_app_ids
|
28
16
|
|
29
|
-
sig do
|
30
|
-
params(
|
31
|
-
name: String,
|
32
|
-
value: T::Boolean,
|
33
|
-
rule_id: String,
|
34
|
-
group_name: T.nilable(String),
|
35
|
-
id_type: String,
|
36
|
-
evaluation_details: T.nilable(Statsig::EvaluationDetails),
|
37
|
-
target_app_ids: T.nilable(T::Array[String])
|
38
|
-
).void
|
39
|
-
end
|
40
17
|
def initialize(
|
41
18
|
name,
|
42
19
|
value: false,
|
@@ -55,7 +32,6 @@ class FeatureGate
|
|
55
32
|
@target_app_ids = target_app_ids
|
56
33
|
end
|
57
34
|
|
58
|
-
sig { params(res: Statsig::ConfigResult).returns(FeatureGate) }
|
59
35
|
def self.from_config_result(res)
|
60
36
|
new(
|
61
37
|
res.name,
|
data/lib/id_list.rb
CHANGED
data/lib/layer.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
# typed: false
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
1
|
##
|
5
2
|
# Contains the current values from Statsig.
|
6
3
|
# Will contain layer default values for all shared parameters in that layer.
|
@@ -9,37 +6,22 @@ require 'sorbet-runtime'
|
|
9
6
|
#
|
10
7
|
# Layers Documentation: https://docs.statsig.com/layers
|
11
8
|
class Layer
|
12
|
-
extend T::Sig
|
13
9
|
|
14
|
-
sig { returns(String) }
|
15
10
|
attr_accessor :name
|
16
11
|
|
17
|
-
sig { returns(String) }
|
18
12
|
attr_accessor :rule_id
|
19
13
|
|
20
|
-
sig { returns(String) }
|
21
14
|
attr_accessor :group_name
|
22
15
|
|
23
|
-
sig do
|
24
|
-
params(
|
25
|
-
name: String,
|
26
|
-
value: T::Hash[String, T.untyped],
|
27
|
-
rule_id: String,
|
28
|
-
group_name: T.nilable(String),
|
29
|
-
allocated_experiment: T.nilable(String),
|
30
|
-
exposure_log_func: T.any(Method, Proc, NilClass)
|
31
|
-
).void
|
32
|
-
end
|
33
16
|
def initialize(name, value = {}, rule_id = '', group_name = nil, allocated_experiment = nil, exposure_log_func = nil)
|
34
17
|
@name = name
|
35
|
-
@value = value
|
18
|
+
@value = value || {}
|
36
19
|
@rule_id = rule_id
|
37
20
|
@group_name = group_name
|
38
21
|
@allocated_experiment = allocated_experiment
|
39
22
|
@exposure_log_func = exposure_log_func
|
40
23
|
end
|
41
24
|
|
42
|
-
sig { params(index: String, default_value: T.untyped).returns(T.untyped) }
|
43
25
|
##
|
44
26
|
# Get the value for the given key (index), falling back to the default_value if it cannot be found.
|
45
27
|
#
|
@@ -55,7 +37,6 @@ class Layer
|
|
55
37
|
@value[index]
|
56
38
|
end
|
57
39
|
|
58
|
-
sig { params(index: String, default_value: T.untyped).returns(T.untyped) }
|
59
40
|
##
|
60
41
|
# Get the value for the given key (index), falling back to the default_value if it cannot be found
|
61
42
|
# or is found to have a different type from the default_value.
|
data/lib/network.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
1
|
require 'http'
|
4
2
|
require 'json'
|
5
3
|
require 'securerandom'
|
6
|
-
|
4
|
+
|
7
5
|
require 'uri_helper'
|
8
6
|
require 'connection_pool'
|
9
7
|
|
@@ -20,9 +18,7 @@ module Statsig
|
|
20
18
|
end
|
21
19
|
|
22
20
|
class Network
|
23
|
-
extend T::Sig
|
24
21
|
|
25
|
-
sig { params(server_secret: String, options: StatsigOptions, backoff_mult: Integer).void }
|
26
22
|
def initialize(server_secret, options, backoff_mult = 10)
|
27
23
|
super()
|
28
24
|
URIHelper.initialize(options)
|
@@ -54,41 +50,18 @@ module Statsig
|
|
54
50
|
end
|
55
51
|
end
|
56
52
|
|
57
|
-
sig do
|
58
|
-
params(since_time: Integer)
|
59
|
-
.returns([T.any(HTTP::Response, NilClass), T.any(StandardError, NilClass)])
|
60
|
-
end
|
61
53
|
def download_config_specs(since_time)
|
62
54
|
get("download_config_specs/#{@server_secret}.json?sinceTime=#{since_time}")
|
63
55
|
end
|
64
56
|
|
65
|
-
class HttpMethod < T::Enum
|
66
|
-
enums do
|
67
|
-
GET = new
|
68
|
-
POST = new
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
sig do
|
73
|
-
params(endpoint: String, retries: Integer, backoff: Integer)
|
74
|
-
.returns([T.any(HTTP::Response, NilClass), T.any(StandardError, NilClass)])
|
75
|
-
end
|
76
57
|
def get(endpoint, retries = 0, backoff = 1)
|
77
|
-
request(
|
58
|
+
request(:GET, endpoint, nil, retries, backoff)
|
78
59
|
end
|
79
60
|
|
80
|
-
sig do
|
81
|
-
params(endpoint: String, body: String, retries: Integer, backoff: Integer)
|
82
|
-
.returns([T.any(HTTP::Response, NilClass), T.any(StandardError, NilClass)])
|
83
|
-
end
|
84
61
|
def post(endpoint, body, retries = 0, backoff = 1)
|
85
|
-
request(
|
62
|
+
request(:POST, endpoint, body, retries, backoff)
|
86
63
|
end
|
87
64
|
|
88
|
-
sig do
|
89
|
-
params(method: HttpMethod, endpoint: String, body: T.nilable(String), retries: Integer, backoff: Integer)
|
90
|
-
.returns([T.any(HTTP::Response, NilClass), T.any(StandardError, NilClass)])
|
91
|
-
end
|
92
65
|
def request(method, endpoint, body, retries = 0, backoff = 1)
|
93
66
|
if @local_mode
|
94
67
|
return nil, nil
|
@@ -107,9 +80,9 @@ module Statsig
|
|
107
80
|
res = @connection_pool.with do |conn|
|
108
81
|
request = conn.headers('STATSIG-CLIENT-TIME' => (Time.now.to_f * 1000).to_i.to_s)
|
109
82
|
case method
|
110
|
-
when
|
83
|
+
when :GET
|
111
84
|
request.get(url)
|
112
|
-
when
|
85
|
+
when :POST
|
113
86
|
request.post(url, body: body)
|
114
87
|
end
|
115
88
|
end
|
@@ -133,7 +106,7 @@ module Statsig
|
|
133
106
|
end
|
134
107
|
|
135
108
|
def post_logs(events)
|
136
|
-
json_body = JSON.generate({
|
109
|
+
json_body = JSON.generate({ events: events, statsigMetadata: Statsig.get_statsig_metadata })
|
137
110
|
post('log_event', json_body, @post_logs_retry_limit)
|
138
111
|
rescue StandardError
|
139
112
|
|
data/lib/spec_store.rb
CHANGED
@@ -1,17 +1,24 @@
|
|
1
|
-
# typed: false
|
2
1
|
require 'net/http'
|
3
2
|
require 'uri'
|
4
3
|
require 'evaluation_details'
|
5
4
|
require 'id_list'
|
6
5
|
require 'concurrent-ruby'
|
7
6
|
require 'hash_utils'
|
7
|
+
require 'api_config'
|
8
8
|
|
9
9
|
module Statsig
|
10
10
|
class SpecStore
|
11
|
-
|
12
11
|
attr_accessor :last_config_sync_time
|
13
12
|
attr_accessor :initial_config_sync_time
|
14
13
|
attr_accessor :init_reason
|
14
|
+
attr_accessor :gates
|
15
|
+
attr_accessor :configs
|
16
|
+
attr_accessor :layers
|
17
|
+
attr_accessor :id_lists
|
18
|
+
attr_accessor :experiment_to_layer
|
19
|
+
attr_accessor :sdk_keys_to_app_ids
|
20
|
+
attr_accessor :hashed_sdk_keys_to_app_ids
|
21
|
+
attr_accessor :unsupported_configs
|
15
22
|
|
16
23
|
def initialize(network, options, error_callback, diagnostics, error_boundary, logger, secret_key)
|
17
24
|
@init_reason = EvaluationReason::UNINITIALIZED
|
@@ -23,25 +30,24 @@ module Statsig
|
|
23
30
|
@rulesets_sync_interval = options.rulesets_sync_interval
|
24
31
|
@id_lists_sync_interval = options.idlists_sync_interval
|
25
32
|
@rules_updated_callback = options.rules_updated_callback
|
26
|
-
@
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
:hashed_sdk_keys_to_app_ids => {}
|
34
|
-
}
|
33
|
+
@gates = {}
|
34
|
+
@configs = {}
|
35
|
+
@layers = {}
|
36
|
+
@id_lists = {}
|
37
|
+
@experiment_to_layer = {}
|
38
|
+
@sdk_keys_to_app_ids = {}
|
39
|
+
@hashed_sdk_keys_to_app_ids = {}
|
35
40
|
@diagnostics = diagnostics
|
36
41
|
@error_boundary = error_boundary
|
37
42
|
@logger = logger
|
38
43
|
@secret_key = secret_key
|
44
|
+
@unsupported_configs = Set.new
|
39
45
|
|
40
46
|
@id_list_thread_pool = Concurrent::FixedThreadPool.new(
|
41
47
|
options.idlist_threadpool_size,
|
42
48
|
name: 'statsig-idlist',
|
43
49
|
max_queue: 100,
|
44
|
-
fallback_policy: :discard
|
50
|
+
fallback_policy: :discard
|
45
51
|
)
|
46
52
|
|
47
53
|
unless @options.bootstrap_values.nil?
|
@@ -53,7 +59,7 @@ module Statsig
|
|
53
59
|
if process_specs(options.bootstrap_values)
|
54
60
|
@init_reason = EvaluationReason::BOOTSTRAP
|
55
61
|
end
|
56
|
-
rescue
|
62
|
+
rescue StandardError
|
57
63
|
puts 'the provided bootstrapValues is not a valid JSON string'
|
58
64
|
ensure
|
59
65
|
tracker.end(success: @init_reason == EvaluationReason::BOOTSTRAP)
|
@@ -96,70 +102,61 @@ module Statsig
|
|
96
102
|
end
|
97
103
|
|
98
104
|
def has_gate?(gate_name)
|
99
|
-
@
|
105
|
+
@gates.key?(gate_name)
|
100
106
|
end
|
101
107
|
|
102
108
|
def has_config?(config_name)
|
103
|
-
@
|
109
|
+
@configs.key?(config_name)
|
104
110
|
end
|
105
111
|
|
106
112
|
def has_layer?(layer_name)
|
107
|
-
@
|
113
|
+
@layers.key?(layer_name)
|
108
114
|
end
|
109
115
|
|
110
116
|
def get_gate(gate_name)
|
111
117
|
return nil unless has_gate?(gate_name)
|
112
|
-
|
118
|
+
|
119
|
+
@gates[gate_name]
|
113
120
|
end
|
114
121
|
|
115
122
|
def get_config(config_name)
|
116
123
|
return nil unless has_config?(config_name)
|
117
|
-
|
124
|
+
|
125
|
+
@configs[config_name]
|
118
126
|
end
|
119
127
|
|
120
128
|
def get_layer(layer_name)
|
121
129
|
return nil unless has_layer?(layer_name)
|
122
|
-
@specs[:layers][layer_name]
|
123
|
-
end
|
124
130
|
|
125
|
-
|
126
|
-
@specs[:gates]
|
127
|
-
end
|
128
|
-
|
129
|
-
def configs
|
130
|
-
@specs[:configs]
|
131
|
-
end
|
132
|
-
|
133
|
-
def layers
|
134
|
-
@specs[:layers]
|
131
|
+
@layers[layer_name]
|
135
132
|
end
|
136
133
|
|
137
134
|
def get_id_list(list_name)
|
138
|
-
@
|
135
|
+
@id_lists[list_name]
|
139
136
|
end
|
140
137
|
|
141
138
|
def has_sdk_key?(sdk_key)
|
142
|
-
@
|
139
|
+
@sdk_keys_to_app_ids.key?(sdk_key)
|
143
140
|
end
|
144
141
|
|
145
142
|
def has_hashed_sdk_key?(hashed_sdk_key)
|
146
|
-
@
|
143
|
+
@hashed_sdk_keys_to_app_ids.key?(hashed_sdk_key)
|
147
144
|
end
|
148
145
|
|
149
146
|
def get_app_id_for_sdk_key(sdk_key)
|
150
147
|
if sdk_key.nil?
|
151
148
|
return nil
|
152
149
|
end
|
153
|
-
|
150
|
+
|
151
|
+
hashed_sdk_key = Statsig::HashUtils.djb2(sdk_key).to_sym
|
154
152
|
if has_hashed_sdk_key?(hashed_sdk_key)
|
155
|
-
return @
|
153
|
+
return @hashed_sdk_keys_to_app_ids[hashed_sdk_key]
|
156
154
|
end
|
157
|
-
return nil unless has_sdk_key?(sdk_key)
|
158
|
-
@specs[:sdk_keys_to_app_ids][sdk_key]
|
159
|
-
end
|
160
155
|
|
161
|
-
|
162
|
-
|
156
|
+
key = sdk_key.to_sym
|
157
|
+
return nil unless has_sdk_key?(key)
|
158
|
+
|
159
|
+
@sdk_keys_to_app_ids[key]
|
163
160
|
end
|
164
161
|
|
165
162
|
def maybe_restart_background_threads
|
@@ -211,6 +208,7 @@ module Statsig
|
|
211
208
|
if @options.data_store.nil?
|
212
209
|
return
|
213
210
|
end
|
211
|
+
|
214
212
|
@options.data_store.set(Interfaces::IDataStore::CONFIG_SPECS_KEY, specs_string)
|
215
213
|
end
|
216
214
|
|
@@ -264,7 +262,10 @@ module Statsig
|
|
264
262
|
end
|
265
263
|
tracker.end(success: @init_reason == EvaluationReason::NETWORK)
|
266
264
|
|
267
|
-
|
265
|
+
unless response.body.nil? or @rules_updated_callback.nil?
|
266
|
+
@rules_updated_callback.call(response.body.to_s,
|
267
|
+
@last_config_sync_time)
|
268
|
+
end
|
268
269
|
end
|
269
270
|
|
270
271
|
nil
|
@@ -283,43 +284,41 @@ module Statsig
|
|
283
284
|
return false
|
284
285
|
end
|
285
286
|
|
286
|
-
specs_json = JSON.parse(specs_string)
|
287
|
+
specs_json = JSON.parse(specs_string, { symbolize_names: true })
|
287
288
|
return false unless specs_json.is_a? Hash
|
288
289
|
|
289
|
-
hashed_sdk_key_used = specs_json[
|
290
|
+
hashed_sdk_key_used = specs_json[:hashed_sdk_key_used]
|
290
291
|
unless hashed_sdk_key_used.nil? or hashed_sdk_key_used == Statsig::HashUtils.djb2(@secret_key)
|
291
292
|
err_boundary.log_exception(Statsig::InvalidSDKKeyResponse.new)
|
292
293
|
return false
|
293
294
|
end
|
294
295
|
|
295
|
-
@last_config_sync_time = specs_json[
|
296
|
-
return false unless specs_json[
|
297
|
-
|
298
|
-
|
299
|
-
|
296
|
+
@last_config_sync_time = specs_json[:time] || @last_config_sync_time
|
297
|
+
return false unless specs_json[:has_updates] == true &&
|
298
|
+
!specs_json[:feature_gates].nil? &&
|
299
|
+
!specs_json[:dynamic_configs].nil? &&
|
300
|
+
!specs_json[:layer_configs].nil?
|
300
301
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
302
|
+
@unsupported_configs.clear()
|
303
|
+
new_gates = process_configs(specs_json[:feature_gates])
|
304
|
+
new_configs = process_configs(specs_json[:dynamic_configs])
|
305
|
+
new_layers = process_configs(specs_json[:layer_configs])
|
305
306
|
|
306
|
-
|
307
|
-
specs_json[
|
308
|
-
specs_json['layer_configs'].each { |layer| new_layers[layer['name']] = layer }
|
309
|
-
specs_json['diagnostics']&.each { |key, value| @diagnostics.sample_rates[key] = value }
|
307
|
+
new_exp_to_layer = {}
|
308
|
+
specs_json[:diagnostics]&.each { |key, value| @diagnostics.sample_rates[key.to_s] = value }
|
310
309
|
|
311
|
-
if specs_json[
|
312
|
-
specs_json[
|
310
|
+
if specs_json[:layers].is_a?(Hash)
|
311
|
+
specs_json[:layers].each do |layer_name, experiments|
|
313
312
|
experiments.each { |experiment_name| new_exp_to_layer[experiment_name] = layer_name }
|
314
|
-
|
313
|
+
end
|
315
314
|
end
|
316
315
|
|
317
|
-
@
|
318
|
-
@
|
319
|
-
@
|
320
|
-
@
|
321
|
-
@
|
322
|
-
@
|
316
|
+
@gates = new_gates
|
317
|
+
@configs = new_configs
|
318
|
+
@layers = new_layers
|
319
|
+
@experiment_to_layer = new_exp_to_layer
|
320
|
+
@sdk_keys_to_app_ids = specs_json[:sdk_keys_to_app_ids] || {}
|
321
|
+
@hashed_sdk_keys_to_app_ids = specs_json[:hashed_sdk_keys_to_app_ids] || {}
|
323
322
|
|
324
323
|
unless from_adapter
|
325
324
|
save_config_specs_to_storage_adapter(specs_string)
|
@@ -327,6 +326,17 @@ module Statsig
|
|
327
326
|
true
|
328
327
|
end
|
329
328
|
|
329
|
+
def process_configs(configs)
|
330
|
+
configs.each_with_object({}) do |config, new_configs|
|
331
|
+
begin
|
332
|
+
new_configs[config[:name]] = APIConfig.from_json(config)
|
333
|
+
rescue UnsupportedConfigException => e
|
334
|
+
@unsupported_configs.add(config[:name])
|
335
|
+
nil
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
330
340
|
def get_id_lists_from_adapter(context)
|
331
341
|
tracker = @diagnostics.track(context, 'data_store_id_lists', 'fetch')
|
332
342
|
cached_values = @options.data_store.get(Interfaces::IDataStore::ID_LISTS_KEY)
|
@@ -345,6 +355,7 @@ module Statsig
|
|
345
355
|
if @options.data_store.nil?
|
346
356
|
return
|
347
357
|
end
|
358
|
+
|
348
359
|
@options.data_store.set(Interfaces::IDataStore::ID_LISTS_KEY, id_lists_raw_json)
|
349
360
|
end
|
350
361
|
|
@@ -357,7 +368,7 @@ module Statsig
|
|
357
368
|
end
|
358
369
|
success = e.nil? && !response.nil?
|
359
370
|
tracker.end(statusCode: code, success: success, sdkRegion: response&.headers&.[]('X-Statsig-Region'))
|
360
|
-
|
371
|
+
unless success
|
361
372
|
return
|
362
373
|
end
|
363
374
|
|
@@ -365,16 +376,17 @@ module Statsig
|
|
365
376
|
server_id_lists = JSON.parse(response)
|
366
377
|
process_id_lists(server_id_lists, context)
|
367
378
|
save_id_lists_to_adapter(response.body.to_s)
|
368
|
-
rescue
|
379
|
+
rescue StandardError
|
369
380
|
# Ignored, will try again
|
370
381
|
end
|
371
382
|
end
|
372
383
|
|
373
384
|
def process_id_lists(new_id_lists, context, from_adapter: false)
|
374
|
-
local_id_lists = @
|
385
|
+
local_id_lists = @id_lists
|
375
386
|
if !new_id_lists.is_a?(Hash) || !local_id_lists.is_a?(Hash)
|
376
387
|
return
|
377
388
|
end
|
389
|
+
|
378
390
|
tasks = []
|
379
391
|
|
380
392
|
tracker = @diagnostics.track(context,
|
@@ -389,7 +401,7 @@ module Statsig
|
|
389
401
|
end
|
390
402
|
|
391
403
|
delete_lists = []
|
392
|
-
local_id_lists.each do |list_name,
|
404
|
+
local_id_lists.each do |list_name, _list|
|
393
405
|
unless new_id_lists.key? list_name
|
394
406
|
delete_lists.push list_name
|
395
407
|
end
|
@@ -425,7 +437,7 @@ module Statsig
|
|
425
437
|
next
|
426
438
|
end
|
427
439
|
|
428
|
-
tasks << Concurrent::Promise.execute(:
|
440
|
+
tasks << Concurrent::Promise.execute(executor: @id_list_thread_pool) do
|
429
441
|
if from_adapter
|
430
442
|
get_single_id_list_from_adapter(local_list, context)
|
431
443
|
else
|
@@ -468,7 +480,7 @@ module Statsig
|
|
468
480
|
content = res.body.to_s
|
469
481
|
success = process_single_id_list(list, context, content, content_length)
|
470
482
|
save_single_id_list_to_adapter(list.name, content) unless success.nil? || !success
|
471
|
-
rescue
|
483
|
+
rescue StandardError
|
472
484
|
tracker.end(success: false)
|
473
485
|
nil
|
474
486
|
end
|
@@ -479,7 +491,7 @@ module Statsig
|
|
479
491
|
begin
|
480
492
|
tracker = @diagnostics.track(context, from_adapter ? 'data_store_id_list' : 'get_id_list', 'process', { url: list.url })
|
481
493
|
unless content.is_a?(String) && (content[0] == '-' || content[0] == '+')
|
482
|
-
@
|
494
|
+
@id_lists.delete(list.name)
|
483
495
|
tracker.end(success: false)
|
484
496
|
return false
|
485
497
|
end
|
@@ -488,6 +500,7 @@ module Statsig
|
|
488
500
|
lines.each do |li|
|
489
501
|
line = li.strip
|
490
502
|
next if line.length <= 1
|
503
|
+
|
491
504
|
op = line[0]
|
492
505
|
id = line[1..line.length]
|
493
506
|
if op == '+'
|
@@ -504,11 +517,10 @@ module Statsig
|
|
504
517
|
end
|
505
518
|
tracker.end(success: true)
|
506
519
|
return true
|
507
|
-
rescue
|
520
|
+
rescue StandardError
|
508
521
|
tracker.end(success: false)
|
509
522
|
return false
|
510
523
|
end
|
511
524
|
end
|
512
|
-
|
513
525
|
end
|
514
526
|
end
|