statsig 1.24.6 → 1.25.0

Sign up to get free protection for your applications and to get access to all the features.
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