statsig 1.14.0 → 1.16.1
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/evaluation_details.rb +1 -0
- data/lib/evaluator.rb +1 -1
- data/lib/interfaces/data_store.rb +18 -0
- data/lib/network.rb +3 -1
- data/lib/spec_store.rb +49 -14
- data/lib/statsig.rb +1 -1
- data/lib/statsig_driver.rb +1 -2
- data/lib/statsig_event.rb +4 -0
- data/lib/statsig_logger.rb +26 -18
- data/lib/statsig_options.rb +4 -1
- data/lib/statsig_user.rb +10 -0
- metadata +23 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4dcb84e4bc8ba66021edba175badb275faf6adfd25ca69f662a8b66a1c1cee64
|
4
|
+
data.tar.gz: e4564a84d37ce348006eddbc6e7ff6371e1493e0a4e13e9ad987653b1f0b266a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c33220e646b1af64499f40989ac4bccffbaf1cbd352f3ab6efc13a0d5246e726a37b95f2bce2c912fcb7b3fb8ed67d487ff9da07f28d01917178cfd8fba2293
|
7
|
+
data.tar.gz: 2ea4f85caede773fc57f84934946f3fde39002d524326e9134ed2cc3410ed02258034b3a81808bc438c7a6d200dfeb5268c16c57a36bcbdce1956424257e1141
|
data/lib/evaluation_details.rb
CHANGED
data/lib/evaluator.rb
CHANGED
@@ -17,7 +17,7 @@ module Statsig
|
|
17
17
|
attr_accessor :spec_store
|
18
18
|
|
19
19
|
def initialize(network, options, error_callback)
|
20
|
-
@spec_store = Statsig::SpecStore.new(network,
|
20
|
+
@spec_store = Statsig::SpecStore.new(network, options, error_callback)
|
21
21
|
@ua_parser = UserAgentParser::Parser.new
|
22
22
|
CountryLookup.initialize
|
23
23
|
|
data/lib/network.rb
CHANGED
@@ -19,7 +19,9 @@ module Statsig
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def post_helper(endpoint, body, retries = 0, backoff = 1)
|
22
|
-
|
22
|
+
if @local_mode
|
23
|
+
return nil, nil
|
24
|
+
end
|
23
25
|
http = HTTP.headers(
|
24
26
|
{"STATSIG-API-KEY" => @server_secret,
|
25
27
|
"STATSIG-CLIENT-TIME" => (Time.now.to_f * 1000).to_i.to_s,
|
data/lib/spec_store.rb
CHANGED
@@ -1,23 +1,27 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
require 'uri'
|
3
|
-
|
4
3
|
require 'evaluation_details'
|
5
4
|
require 'id_list'
|
6
5
|
|
7
6
|
module Statsig
|
8
7
|
class SpecStore
|
8
|
+
|
9
|
+
CONFIG_SPECS_KEY = "statsig.cache"
|
10
|
+
|
9
11
|
attr_accessor :last_config_sync_time
|
10
12
|
attr_accessor :initial_config_sync_time
|
11
13
|
attr_accessor :init_reason
|
12
14
|
|
13
|
-
def initialize(network,
|
15
|
+
def initialize(network, options, error_callback)
|
14
16
|
@init_reason = EvaluationReason::UNINITIALIZED
|
15
17
|
@network = network
|
18
|
+
@options = options
|
19
|
+
@error_callback = error_callback
|
16
20
|
@last_config_sync_time = 0
|
17
21
|
@initial_config_sync_time = 0
|
18
|
-
@rulesets_sync_interval = rulesets_sync_interval
|
19
|
-
@id_lists_sync_interval =
|
20
|
-
@rules_updated_callback = rules_updated_callback
|
22
|
+
@rulesets_sync_interval = options.rulesets_sync_interval
|
23
|
+
@id_lists_sync_interval = options.idlists_sync_interval
|
24
|
+
@rules_updated_callback = options.rules_updated_callback
|
21
25
|
@specs = {
|
22
26
|
:gates => {},
|
23
27
|
:configs => {},
|
@@ -26,9 +30,11 @@ module Statsig
|
|
26
30
|
:experiment_to_layer => {}
|
27
31
|
}
|
28
32
|
|
29
|
-
unless bootstrap_values.nil?
|
33
|
+
unless @options.bootstrap_values.nil?
|
30
34
|
begin
|
31
|
-
if
|
35
|
+
if !@options.data_store.nil?
|
36
|
+
puts 'data_store gets priority over bootstrap_values. bootstrap_values will be ignored'
|
37
|
+
elsif process(options.bootstrap_values)
|
32
38
|
@init_reason = EvaluationReason::BOOTSTRAP
|
33
39
|
end
|
34
40
|
rescue
|
@@ -36,7 +42,11 @@ module Statsig
|
|
36
42
|
end
|
37
43
|
end
|
38
44
|
|
39
|
-
@
|
45
|
+
unless @options.data_store.nil?
|
46
|
+
@options.data_store.init
|
47
|
+
load_from_storage_adapter
|
48
|
+
end
|
49
|
+
|
40
50
|
download_config_specs
|
41
51
|
@initial_config_sync_time = @last_config_sync_time == 0 ? -1 : @last_config_sync_time
|
42
52
|
get_id_lists
|
@@ -52,6 +62,9 @@ module Statsig
|
|
52
62
|
def shutdown
|
53
63
|
@config_sync_thread&.exit
|
54
64
|
@id_lists_sync_thread&.exit
|
65
|
+
unless @options.data_store.nil?
|
66
|
+
@options.data_store.shutdown
|
67
|
+
end
|
55
68
|
end
|
56
69
|
|
57
70
|
def has_gate?(gate_name)
|
@@ -100,10 +113,26 @@ module Statsig
|
|
100
113
|
|
101
114
|
private
|
102
115
|
|
116
|
+
def load_from_storage_adapter
|
117
|
+
cached_values = @options.data_store.get(CONFIG_SPECS_KEY)
|
118
|
+
if cached_values.nil?
|
119
|
+
return
|
120
|
+
end
|
121
|
+
process(cached_values, true)
|
122
|
+
@init_reason = EvaluationReason::DATA_ADAPTER
|
123
|
+
end
|
124
|
+
|
125
|
+
def save_to_storage_adapter(specs_string)
|
126
|
+
if @options.data_store.nil?
|
127
|
+
return
|
128
|
+
end
|
129
|
+
@options.data_store.set(CONFIG_SPECS_KEY, specs_string)
|
130
|
+
end
|
131
|
+
|
103
132
|
def sync_config_specs
|
104
133
|
Thread.new do
|
105
134
|
loop do
|
106
|
-
sleep @rulesets_sync_interval
|
135
|
+
sleep @options.rulesets_sync_interval
|
107
136
|
download_config_specs
|
108
137
|
end
|
109
138
|
end
|
@@ -127,7 +156,7 @@ module Statsig
|
|
127
156
|
begin
|
128
157
|
response, e = @network.post_helper('download_config_specs', JSON.generate({ 'sinceTime' => @last_config_sync_time }))
|
129
158
|
if e.nil?
|
130
|
-
if process(
|
159
|
+
if !response.nil? and process(response.body)
|
131
160
|
@init_reason = EvaluationReason::NETWORK
|
132
161
|
@rules_updated_callback.call(response.body.to_s, @last_config_sync_time) unless response.body.nil? or @rules_updated_callback.nil?
|
133
162
|
end
|
@@ -140,13 +169,15 @@ module Statsig
|
|
140
169
|
end
|
141
170
|
end
|
142
171
|
|
143
|
-
def process(
|
144
|
-
if
|
172
|
+
def process(specs_string, from_adapter = false)
|
173
|
+
if specs_string.nil?
|
145
174
|
return false
|
146
175
|
end
|
147
176
|
|
148
|
-
|
177
|
+
specs_json = JSON.parse(specs_string)
|
178
|
+
return false unless specs_json.is_a? Hash
|
149
179
|
|
180
|
+
@last_config_sync_time = specs_json['time'] || @last_config_sync_time
|
150
181
|
return false unless specs_json['has_updates'] == true &&
|
151
182
|
!specs_json['feature_gates'].nil? &&
|
152
183
|
!specs_json['dynamic_configs'].nil? &&
|
@@ -171,6 +202,10 @@ module Statsig
|
|
171
202
|
@specs[:configs] = new_configs
|
172
203
|
@specs[:layers] = new_layers
|
173
204
|
@specs[:experiment_to_layer] = new_exp_to_layer
|
205
|
+
|
206
|
+
unless from_adapter
|
207
|
+
save_to_storage_adapter(specs_string)
|
208
|
+
end
|
174
209
|
true
|
175
210
|
end
|
176
211
|
|
@@ -253,7 +288,7 @@ module Statsig
|
|
253
288
|
line = li.strip
|
254
289
|
next if line.length <= 1
|
255
290
|
op = line[0]
|
256
|
-
id = line[1..]
|
291
|
+
id = line[1..line.length]
|
257
292
|
if op == '+'
|
258
293
|
ids_clone.add(id)
|
259
294
|
elsif op == '-'
|
data/lib/statsig.rb
CHANGED
data/lib/statsig_driver.rb
CHANGED
@@ -94,7 +94,7 @@ class StatsigDriver
|
|
94
94
|
|
95
95
|
def shutdown
|
96
96
|
@shutdown = true
|
97
|
-
@logger.
|
97
|
+
@logger.shutdown
|
98
98
|
@evaluator.shutdown
|
99
99
|
end
|
100
100
|
|
@@ -115,7 +115,6 @@ class StatsigDriver
|
|
115
115
|
|
116
116
|
def maybe_restart_background_threads
|
117
117
|
@evaluator.maybe_restart_background_threads
|
118
|
-
@logger.maybe_restart_background_threads
|
119
118
|
end
|
120
119
|
|
121
120
|
private
|
data/lib/statsig_event.rb
CHANGED
data/lib/statsig_logger.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'statsig_event'
|
2
|
+
require 'concurrent-ruby'
|
2
3
|
|
3
4
|
$gate_exposure_event = 'statsig::gate_exposure'
|
4
5
|
$config_exposure_event = 'statsig::config_exposure'
|
@@ -9,14 +10,23 @@ module Statsig
|
|
9
10
|
def initialize(network, options)
|
10
11
|
@network = network
|
11
12
|
@events = []
|
12
|
-
@background_flush = periodic_flush
|
13
13
|
@options = options
|
14
|
+
|
15
|
+
@logging_pool = Concurrent::ThreadPoolExecutor.new(
|
16
|
+
min_threads: [2, Concurrent.processor_count].min,
|
17
|
+
max_threads: [2, Concurrent.processor_count].max,
|
18
|
+
# max jobs pending before we start dropping
|
19
|
+
max_queue: [2, Concurrent.processor_count].max * 5,
|
20
|
+
fallback_policy: :discard,
|
21
|
+
)
|
22
|
+
|
23
|
+
@background_flush = periodic_flush
|
14
24
|
end
|
15
25
|
|
16
26
|
def log_event(event)
|
17
27
|
@events.push(event)
|
18
28
|
if @events.length >= @options.logging_max_buffer_size
|
19
|
-
|
29
|
+
flush_async
|
20
30
|
end
|
21
31
|
end
|
22
32
|
|
@@ -83,10 +93,20 @@ module Statsig
|
|
83
93
|
end
|
84
94
|
end
|
85
95
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
96
|
+
def shutdown
|
97
|
+
@background_flush&.exit
|
98
|
+
@logging_pool.shutdown
|
99
|
+
@logging_pool.wait_for_termination(timeout = 3)
|
100
|
+
flush
|
101
|
+
end
|
102
|
+
|
103
|
+
def flush_async
|
104
|
+
@logging_pool.post do
|
105
|
+
flush
|
89
106
|
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def flush
|
90
110
|
if @events.length == 0
|
91
111
|
return
|
92
112
|
end
|
@@ -94,19 +114,7 @@ module Statsig
|
|
94
114
|
@events = []
|
95
115
|
flush_events = events_clone.map { |e| e.serialize }
|
96
116
|
|
97
|
-
|
98
|
-
@network.post_logs(flush_events)
|
99
|
-
else
|
100
|
-
Thread.new do
|
101
|
-
@network.post_logs(flush_events)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def maybe_restart_background_threads
|
107
|
-
if @background_flush.nil? or !@background_flush.alive?
|
108
|
-
@background_flush = periodic_flush
|
109
|
-
end
|
117
|
+
@network.post_logs(flush_events)
|
110
118
|
end
|
111
119
|
|
112
120
|
private
|
data/lib/statsig_options.rb
CHANGED
@@ -8,6 +8,7 @@ class StatsigOptions
|
|
8
8
|
attr_accessor :local_mode
|
9
9
|
attr_accessor :bootstrap_values
|
10
10
|
attr_accessor :rules_updated_callback
|
11
|
+
attr_accessor :data_store
|
11
12
|
|
12
13
|
def initialize(
|
13
14
|
environment=nil,
|
@@ -18,7 +19,8 @@ class StatsigOptions
|
|
18
19
|
logging_max_buffer_size: 1000,
|
19
20
|
local_mode: false,
|
20
21
|
bootstrap_values: nil,
|
21
|
-
rules_updated_callback: nil
|
22
|
+
rules_updated_callback: nil,
|
23
|
+
data_store: nil)
|
22
24
|
@environment = environment.is_a?(Hash) ? environment : nil
|
23
25
|
@api_url_base = api_url_base
|
24
26
|
@rulesets_sync_interval = rulesets_sync_interval
|
@@ -28,5 +30,6 @@ class StatsigOptions
|
|
28
30
|
@local_mode = local_mode
|
29
31
|
@bootstrap_values = bootstrap_values
|
30
32
|
@rules_updated_callback = rules_updated_callback
|
33
|
+
@data_store = data_store
|
31
34
|
end
|
32
35
|
end
|
data/lib/statsig_user.rb
CHANGED
@@ -19,6 +19,16 @@ class StatsigUser
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def initialize(user_hash)
|
22
|
+
@user_id = nil
|
23
|
+
@email = nil
|
24
|
+
@ip = nil
|
25
|
+
@user_agent = nil
|
26
|
+
@country = nil
|
27
|
+
@locale = nil
|
28
|
+
@app_version = nil
|
29
|
+
@custom = nil
|
30
|
+
@private_attributes = nil
|
31
|
+
@custom_ids = nil
|
22
32
|
@statsig_environment = Hash.new
|
23
33
|
if user_hash.is_a?(Hash)
|
24
34
|
@user_id = user_hash['userID'] || user_hash['user_id']
|
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: 1.
|
4
|
+
version: 1.16.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Statsig, Inc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '2.
|
19
|
+
version: '2.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '2.
|
26
|
+
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: webmock
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,18 +102,32 @@ dependencies:
|
|
102
102
|
version: '6.0'
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: ip3country
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - '='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.1.1
|
110
|
+
type: :runtime
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - '='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 0.1.1
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: concurrent-ruby
|
105
119
|
requirement: !ruby/object:Gem::Requirement
|
106
120
|
requirements:
|
107
121
|
- - "~>"
|
108
122
|
- !ruby/object:Gem::Version
|
109
|
-
version: '
|
123
|
+
version: '1.1'
|
110
124
|
type: :runtime
|
111
125
|
prerelease: false
|
112
126
|
version_requirements: !ruby/object:Gem::Requirement
|
113
127
|
requirements:
|
114
128
|
- - "~>"
|
115
129
|
- !ruby/object:Gem::Version
|
116
|
-
version: '
|
130
|
+
version: '1.1'
|
117
131
|
description: Statsig server SDK for feature gates and experimentation in Ruby
|
118
132
|
email: support@statsig.com
|
119
133
|
executables: []
|
@@ -127,6 +141,7 @@ files:
|
|
127
141
|
- lib/evaluation_helpers.rb
|
128
142
|
- lib/evaluator.rb
|
129
143
|
- lib/id_list.rb
|
144
|
+
- lib/interfaces/data_store.rb
|
130
145
|
- lib/layer.rb
|
131
146
|
- lib/network.rb
|
132
147
|
- lib/spec_store.rb
|
@@ -148,14 +163,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
148
163
|
requirements:
|
149
164
|
- - ">="
|
150
165
|
- !ruby/object:Gem::Version
|
151
|
-
version:
|
166
|
+
version: 2.5.0
|
152
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
168
|
requirements:
|
154
169
|
- - ">="
|
155
170
|
- !ruby/object:Gem::Version
|
156
171
|
version: '0'
|
157
172
|
requirements: []
|
158
|
-
rubygems_version: 3.3.
|
173
|
+
rubygems_version: 3.3.22
|
159
174
|
signing_key:
|
160
175
|
specification_version: 4
|
161
176
|
summary: Statsig server SDK for Ruby
|