statsig 1.24.6 → 1.25.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29818b483f3950c841a00a05ee3007414cc759498d7656703049417c43cbbae5
4
- data.tar.gz: 36c190613ab7fded21de40e82c238c3c8374e6efba502a6774752a15d796e07d
3
+ metadata.gz: 267f2a16a3bb05a6b046d493bfe98f00b7c083f387eba7862641801ec0579b2b
4
+ data.tar.gz: a20de08fe3b12bcba40795ec1ff53ce5d3c2c27aca3ab41d72541a49e730414c
5
5
  SHA512:
6
- metadata.gz: 30e3d1941bb46e4eb21469f82d2f398e1380fc144b1076f28e521081a9de052bf96ad27821ca93c515e3e308ca8d793dff75a504435a792c008b4623effeb6a5
7
- data.tar.gz: 80eb7090f03d1dcb2a8e78492c6d80fe33e364fea1446330ad30c17eb06dbe8486f7ab1d2776e53e9f3b058f7c4925d4d89ce1f08494e3fd814928c3ac4bd537
6
+ metadata.gz: e7afa3f47ea19f3d759a648f12bd98c8e56c1c757f2c86bc72859ace8ca081e205af90f315cd26c08598fed408a8b4163b452e2312066120d5ead9644f1028ec
7
+ data.tar.gz: d671a37cf7ad21212d71ad90c8fddab13110641a278c475c6f4cec3ff922c0d6b6bceaa1367b902933db481be56601af2ab203c03768a65e9dd959fb900a2438
data/lib/evaluator.rb CHANGED
@@ -6,7 +6,7 @@ require 'evaluation_helpers'
6
6
  require 'client_initialize_helpers'
7
7
  require 'spec_store'
8
8
  require 'time'
9
- require 'user_agent_parser'
9
+ require 'ua_parser'
10
10
  require 'evaluation_details'
11
11
  require 'user_agent_parser/operating_system'
12
12
 
@@ -19,8 +19,8 @@ module Statsig
19
19
 
20
20
  def initialize(network, options, error_callback, init_diagnostics = nil)
21
21
  @spec_store = Statsig::SpecStore.new(network, options, error_callback, init_diagnostics)
22
- @ua_parser = UserAgentParser::Parser.new
23
- CountryLookup.initialize
22
+ UAParser.initialize_async
23
+ CountryLookup.initialize_async
24
24
 
25
25
  @gate_overrides = {}
26
26
  @config_overrides = {}
@@ -449,16 +449,16 @@ module Statsig
449
449
 
450
450
  case field.downcase
451
451
  when 'os_name', 'osname'
452
- os = @ua_parser.parse_os(ua)
452
+ os = UAParser.parse_os(ua)
453
453
  return os&.family
454
454
  when 'os_version', 'osversion'
455
- os = @ua_parser.parse_os(ua)
455
+ os = UAParser.parse_os(ua)
456
456
  return os&.version unless os&.version.nil?
457
457
  when 'browser_name', 'browsername'
458
- parsed = @ua_parser.parse_ua(ua)
458
+ parsed = UAParser.parse_ua(ua)
459
459
  return parsed.family
460
460
  when 'browser_version', 'browserversion'
461
- parsed = @ua_parser.parse_ua(ua)
461
+ parsed = UAParser.parse_ua(ua)
462
462
  return parsed.version.to_s
463
463
  else
464
464
  nil
data/lib/network.rb CHANGED
@@ -33,6 +33,7 @@ module Statsig
33
33
  @local_mode = options.local_mode
34
34
  @timeout = options.network_timeout
35
35
  @backoff_multiplier = backoff_mult
36
+ @post_logs_retry_backoff = options.post_logs_retry_backoff
36
37
  @post_logs_retry_limit = options.post_logs_retry_limit
37
38
  @session_id = SecureRandom.uuid
38
39
  end
@@ -59,6 +60,13 @@ module Statsig
59
60
  http = http.timeout(@timeout)
60
61
  end
61
62
  backoff_adjusted = backoff > 10 ? backoff += Random.rand(10) : backoff # to deter overlap
63
+ if @post_logs_retry_backoff
64
+ if @post_logs_retry_backoff.is_a? Integer
65
+ backoff_adjusted = @post_logs_retry_backoff
66
+ else
67
+ backoff_adjusted = @post_logs_retry_backoff.call(retries)
68
+ end
69
+ end
62
70
  begin
63
71
  res = http.post(@api + endpoint, body: body)
64
72
  rescue StandardError => e
data/lib/spec_store.rb CHANGED
@@ -32,6 +32,7 @@ module Statsig
32
32
 
33
33
  @id_list_thread_pool = Concurrent::FixedThreadPool.new(
34
34
  options.idlist_threadpool_size,
35
+ name: 'statsig-idlist',
35
36
  max_queue: 100,
36
37
  fallback_policy: :discard,
37
38
  )
@@ -309,6 +310,16 @@ module Statsig
309
310
 
310
311
  init_diagnostics&.mark("get_id_lists", "start", "process", new_id_lists.length)
311
312
 
313
+ delete_lists = []
314
+ local_id_lists.each do |list_name, list|
315
+ unless new_id_lists.key? list_name
316
+ delete_lists.push list_name
317
+ end
318
+ end
319
+ delete_lists.each do |list_name|
320
+ local_id_lists.delete list_name
321
+ end
322
+
312
323
  new_id_lists.each do |list_name, list|
313
324
  new_list = IDList.new(list)
314
325
  local_list = get_id_list(list_name)
@@ -346,21 +357,7 @@ module Statsig
346
357
  end
347
358
 
348
359
  result = Concurrent::Promise.all?(*tasks).execute.wait(@id_lists_sync_interval)
349
- if result.state != :fulfilled
350
- init_diagnostics&.mark("get_id_lists", "end", "process", false)
351
- return # timed out
352
- end
353
-
354
- delete_lists = []
355
- local_id_lists.each do |list_name, list|
356
- unless new_id_lists.key? list_name
357
- delete_lists.push list_name
358
- end
359
- end
360
- delete_lists.each do |list_name|
361
- local_id_lists.delete list_name
362
- end
363
- init_diagnostics&.mark("get_id_lists", "end", "process", true)
360
+ init_diagnostics&.mark("get_id_lists", "end", "process", result.state == :fulfilled)
364
361
  end
365
362
 
366
363
  def get_single_id_list_from_adapter(list)
@@ -15,10 +15,11 @@ module Statsig
15
15
  @options = options
16
16
 
17
17
  @logging_pool = Concurrent::ThreadPoolExecutor.new(
18
- min_threads: [2, Concurrent.processor_count].min,
19
- max_threads: [5, Concurrent.processor_count].min,
18
+ name: 'statsig-logger',
19
+ min_threads: @options.logger_threadpool_size,
20
+ max_threads: @options.logger_threadpool_size,
20
21
  # max jobs pending before we start dropping
21
- max_queue: [5, Concurrent.processor_count].min * 5,
22
+ max_queue: 100,
22
23
  fallback_policy: :discard
23
24
  )
24
25
 
@@ -106,7 +107,7 @@ module Statsig
106
107
  Thread.new do
107
108
  loop do
108
109
  sleep @options.logging_interval_seconds
109
- flush
110
+ flush_async
110
111
  @interval += 1
111
112
  @deduper.clear if @interval % 2 == 0
112
113
  end
@@ -64,6 +64,11 @@ class StatsigOptions
64
64
  # default: 3
65
65
  attr_accessor :idlist_threadpool_size
66
66
 
67
+ sig { returns(Integer) }
68
+ # The number of threads allocated to posting event logs.
69
+ # default: 3
70
+ attr_accessor :logger_threadpool_size
71
+
67
72
  sig { returns(T::Boolean) }
68
73
  # Should diagnostics be logged. These include performance metrics for initialize.
69
74
  # default: false
@@ -83,6 +88,11 @@ class StatsigOptions
83
88
  # Number of times to retry sending a batch of failed log events
84
89
  attr_accessor :post_logs_retry_limit
85
90
 
91
+ sig { returns(T.any(Method, Proc, Integer, NilClass)) }
92
+ # The number of seconds, or a function that returns the number of seconds based on the number of retries remaining
93
+ # which overrides the default backoff time between retries
94
+ attr_accessor :post_logs_retry_backoff
95
+
86
96
  sig do
87
97
  params(
88
98
  environment: T.any(T::Hash[String, String], NilClass),
@@ -96,10 +106,12 @@ class StatsigOptions
96
106
  rules_updated_callback: T.any(Method, Proc, NilClass),
97
107
  data_store: T.any(Statsig::Interfaces::IDataStore, NilClass),
98
108
  idlist_threadpool_size: Integer,
109
+ logger_threadpool_size: Integer,
99
110
  disable_diagnostics_logging: T::Boolean,
100
111
  disable_sorbet_logging_handlers: T::Boolean,
101
112
  network_timeout: T.any(Integer, NilClass),
102
- post_logs_retry_limit: Integer
113
+ post_logs_retry_limit: Integer,
114
+ post_logs_retry_backoff: T.any(Method, Proc, Integer, NilClass)
103
115
  ).void
104
116
  end
105
117
 
@@ -115,10 +127,12 @@ class StatsigOptions
115
127
  rules_updated_callback: nil,
116
128
  data_store: nil,
117
129
  idlist_threadpool_size: 3,
130
+ logger_threadpool_size: 3,
118
131
  disable_diagnostics_logging: false,
119
132
  disable_sorbet_logging_handlers: false,
120
133
  network_timeout: nil,
121
- post_logs_retry_limit: 3)
134
+ post_logs_retry_limit: 3,
135
+ post_logs_retry_backoff: nil)
122
136
  @environment = environment.is_a?(Hash) ? environment : nil
123
137
  @api_url_base = api_url_base
124
138
  @rulesets_sync_interval = rulesets_sync_interval
@@ -130,9 +144,11 @@ class StatsigOptions
130
144
  @rules_updated_callback = rules_updated_callback
131
145
  @data_store = data_store
132
146
  @idlist_threadpool_size = idlist_threadpool_size
147
+ @logger_threadpool_size = logger_threadpool_size
133
148
  @disable_diagnostics_logging = disable_diagnostics_logging
134
149
  @disable_sorbet_logging_handlers = disable_sorbet_logging_handlers
135
150
  @network_timeout = network_timeout
136
151
  @post_logs_retry_limit = post_logs_retry_limit
152
+ @post_logs_retry_backoff = post_logs_retry_backoff
137
153
  end
138
154
  end
data/lib/ua_parser.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 'user_agent_parser'
2
+
3
+ module UAParser
4
+ class Parser
5
+ def initialize
6
+ @ua_parser = UserAgentParser::Parser.new
7
+ end
8
+
9
+ def parse_os(*args)
10
+ @ua_parser.parse_os(*args)
11
+ end
12
+
13
+ def parse_ua(*args)
14
+ @ua_parser.parse_ua(*args)
15
+ end
16
+
17
+ def parse_device(*args)
18
+ @ua_parser.parse_device(*args)
19
+ end
20
+ end
21
+
22
+ def self.initialize
23
+ if !@initialize_bg_thread.nil? && @initialize_bg_thread.alive?
24
+ @initialize_bg_thread.kill.join
25
+ end
26
+ @parser = Parser.new
27
+ end
28
+
29
+ def self.initialize_async
30
+ if !@initialize_bg_thread.nil? && @initialize_bg_thread.alive?
31
+ @initialize_bg_thread.kill.join
32
+ end
33
+ @initialize_bg_thread = Thread.new { @parser = Parser.new }
34
+ @initialize_bg_thread
35
+ end
36
+
37
+ def self.parse_os(*args)
38
+ if @parser.nil?
39
+ initialize
40
+ end
41
+ @parser.parse_os(*args)
42
+ end
43
+
44
+ def self.parse_ua(*args)
45
+ if @parser.nil?
46
+ initialize
47
+ end
48
+ @parser.parse_ua(*args)
49
+ end
50
+
51
+ def self.parse_device(*args)
52
+ if @parser.nil?
53
+ initialize
54
+ end
55
+ @parser.parse_device(*args)
56
+ end
57
+ 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: 1.24.6
4
+ version: 1.25.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: 2023-05-11 00:00:00.000000000 Z
11
+ date: 2023-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -230,16 +230,16 @@ dependencies:
230
230
  name: ip3country
231
231
  requirement: !ruby/object:Gem::Requirement
232
232
  requirements:
233
- - - '='
233
+ - - "~>"
234
234
  - !ruby/object:Gem::Version
235
- version: 0.1.1
235
+ version: 0.2.1
236
236
  type: :runtime
237
237
  prerelease: false
238
238
  version_requirements: !ruby/object:Gem::Requirement
239
239
  requirements:
240
- - - '='
240
+ - - "~>"
241
241
  - !ruby/object:Gem::Version
242
- version: 0.1.1
242
+ version: 0.2.1
243
243
  - !ruby/object:Gem::Dependency
244
244
  name: sorbet-runtime
245
245
  requirement: !ruby/object:Gem::Requirement
@@ -294,6 +294,7 @@ files:
294
294
  - lib/statsig_logger.rb
295
295
  - lib/statsig_options.rb
296
296
  - lib/statsig_user.rb
297
+ - lib/ua_parser.rb
297
298
  homepage: https://rubygems.org/gems/statsig
298
299
  licenses:
299
300
  - ISC