posthog-ruby 3.14.2 → 3.14.3

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: 5a92261df7b02c5a549f4969422323c5d2c911ec16990fdb4861acc2ca76c3f3
4
- data.tar.gz: bb5d161962343c95e628ddeb5e5bf053ad2d3c74737dbb4ae347e5a37077c82c
3
+ metadata.gz: 78690fdd0687ca0ba5ca1580bd38be10ee4ca8af77886ba7613556f27cadc882
4
+ data.tar.gz: 01cefb30c994729d2950cfc9d5701bdf29dbf8555101a0cbc7febd7be9e5a81f
5
5
  SHA512:
6
- metadata.gz: 2c8a69d40d6dda952c2a3ef0d2b1def8ac9c2e6f8acf87e53aae5b62ca9f538628a87c1451475034917f8a003f2f7b901cbd8c41c16c5b2c0d17381a62bdc192
7
- data.tar.gz: a5be03ab5250513092e907238fe0ffcdcf8cdf6124a8cc20cd4eeabdd0123b8e7db9c88c0bf40d861eccfc10f551f0871ba29b075cbaf32172003d8cf4e9f9d6
6
+ metadata.gz: fbfa25966ae2e7a7275bbb11faa1fa1b1b9813dfc08540cd5e26693c765db48c3d3faa3fe1c542b044693cded6676a71465eb3ce2092428d7b4cc3c9567bf47b
7
+ data.tar.gz: 458ae4437710f4f6adf0e62271cf8cf5b8788334bb35ed016dc4e1ccfdbc7434ba29c1efad5d58243aad97dffb3a8a8949a2571c97557ed4e036809d3b1e4ffe
@@ -67,6 +67,9 @@ module PostHog
67
67
  # in seconds. Defaults to 30.
68
68
  # @option opts [Integer] :feature_flag_request_timeout_seconds How long to wait for feature flag evaluation,
69
69
  # in seconds. Defaults to 3.
70
+ # @option opts [Integer] :feature_flag_request_max_retries How many times to retry a flag request after a
71
+ # transient network error. Each retry sleeps on the calling thread before retrying, so this adds to
72
+ # worst-case latency. Defaults to 1. Set to 0 to disable retrying.
70
73
  # @option opts [Proc] :before_send A callback that receives the event hash and should return either a modified
71
74
  # hash to be sent to PostHog or nil to prevent the event from being sent. e.g. `before_send: ->(event) { event }`.
72
75
  # @option opts [Boolean] :disable_singleton_warning +true+ to suppress the warning when multiple clients share
@@ -140,7 +143,8 @@ module PostHog
140
143
  opts[:host],
141
144
  opts[:feature_flag_request_timeout_seconds] || Defaults::FeatureFlags::FLAG_REQUEST_TIMEOUT_SECONDS,
142
145
  opts[:on_error],
143
- flag_definition_cache_provider: opts[:flag_definition_cache_provider]
146
+ flag_definition_cache_provider: opts[:flag_definition_cache_provider],
147
+ feature_flag_request_max_retries: opts[:feature_flag_request_max_retries]
144
148
  )
145
149
  end
146
150
 
@@ -19,6 +19,10 @@ module PostHog
19
19
 
20
20
  module FeatureFlags
21
21
  FLAG_REQUEST_TIMEOUT_SECONDS = 3
22
+ # Number of retries for a flag request after a transient network error.
23
+ # Flag requests are stateless and cause no server-side mutation, so
24
+ # retrying is safe.
25
+ FLAG_REQUEST_MAX_RETRIES = 1
22
26
  end
23
27
 
24
28
  module Queue
@@ -5,6 +5,8 @@ require 'net/http'
5
5
  require 'json'
6
6
  require 'posthog/version'
7
7
  require 'posthog/logging'
8
+ require 'posthog/defaults'
9
+ require 'posthog/backoff_policy'
8
10
  require 'posthog/feature_flag'
9
11
  require 'posthog/flag_definition_cache'
10
12
  require 'digest'
@@ -34,6 +36,8 @@ module PostHog
34
36
  # @param feature_flag_request_timeout_seconds [Integer] Timeout for feature flag requests.
35
37
  # @param on_error [Proc, nil] Callback invoked as `on_error.call(status, error)`.
36
38
  # @param flag_definition_cache_provider [Object, nil] Optional {FlagDefinitionCacheProvider} implementation.
39
+ # @param feature_flag_request_max_retries [Integer, nil] Retries after a transient network error on a flag
40
+ # request. Defaults to {Defaults::FeatureFlags::FLAG_REQUEST_MAX_RETRIES}. Set to 0 to disable retrying.
37
41
  def initialize(
38
42
  polling_interval,
39
43
  personal_api_key,
@@ -41,7 +45,8 @@ module PostHog
41
45
  host,
42
46
  feature_flag_request_timeout_seconds,
43
47
  on_error = nil,
44
- flag_definition_cache_provider: nil
48
+ flag_definition_cache_provider: nil,
49
+ feature_flag_request_max_retries: nil
45
50
  )
46
51
  @polling_interval = polling_interval || 30
47
52
  @personal_api_key = personal_api_key
@@ -53,6 +58,8 @@ module PostHog
53
58
  @loaded_flags_successfully_once = Concurrent::AtomicBoolean.new
54
59
  @feature_flags_by_key = nil
55
60
  @feature_flag_request_timeout_seconds = feature_flag_request_timeout_seconds
61
+ @feature_flag_request_max_retries =
62
+ feature_flag_request_max_retries || Defaults::FeatureFlags::FLAG_REQUEST_MAX_RETRIES
56
63
  @on_error = on_error || proc { |status, error| }
57
64
  @quota_limited = Concurrent::AtomicBoolean.new(false)
58
65
  @flags_etag = Concurrent::AtomicReference.new(nil)
@@ -1240,12 +1247,24 @@ module PostHog
1240
1247
  _request(uri, req, @feature_flag_request_timeout_seconds)
1241
1248
  end
1242
1249
 
1243
- # rubocop:disable Lint/ShadowedException
1250
+ # Transient network errors that are safe to retry. Flag requests are
1251
+ # retry-safe (stateless reads and evaluations, no server-side mutation), so
1252
+ # a one-off blip (TCP retransmit, TLS jitter, an edge/proxy hiccup) should
1253
+ # be absorbed by a retry rather than surfaced to the caller.
1254
+ RETRYABLE_REQUEST_ERRORS = [
1255
+ Timeout::Error, # covers Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout
1256
+ Errno::ECONNRESET,
1257
+ EOFError
1258
+ ].freeze
1259
+
1244
1260
  def _request(uri, request_object, timeout = nil, include_etag: false)
1245
1261
  request_object['User-Agent'] = "posthog-ruby/#{PostHog::VERSION}"
1246
1262
  request_timeout = timeout || 10
1263
+ backoff_policy = nil
1264
+ attempts = 0
1247
1265
 
1248
1266
  begin
1267
+ attempts += 1
1249
1268
  Net::HTTP.start(
1250
1269
  uri.hostname,
1251
1270
  uri.port,
@@ -1279,20 +1298,24 @@ module PostHog
1279
1298
  return error_response
1280
1299
  end
1281
1300
  end
1282
- rescue Timeout::Error,
1283
- Errno::EINVAL,
1284
- Errno::ECONNRESET,
1285
- EOFError,
1301
+ rescue *RETRYABLE_REQUEST_ERRORS => e
1302
+ if attempts <= @feature_flag_request_max_retries
1303
+ backoff_policy ||= BackoffPolicy.new
1304
+ interval = backoff_policy.next_interval.to_f / 1000
1305
+ logger.debug("Retrying request to #{_mask_tokens_in_url(uri.to_s)} after #{e.class} (attempt #{attempts})")
1306
+ sleep(interval)
1307
+ retry
1308
+ end
1309
+ logger.debug("Unable to complete request to #{_mask_tokens_in_url(uri.to_s)}")
1310
+ raise
1311
+ rescue Errno::EINVAL,
1286
1312
  Net::HTTPBadResponse,
1287
1313
  Net::HTTPHeaderSyntaxError,
1288
- Net::ReadTimeout,
1289
- Net::WriteTimeout,
1290
1314
  Net::ProtocolError
1291
- logger.debug("Unable to complete request to #{uri}")
1315
+ logger.debug("Unable to complete request to #{_mask_tokens_in_url(uri.to_s)}")
1292
1316
  raise
1293
1317
  end
1294
1318
  end
1295
- # rubocop:enable Lint/ShadowedException
1296
1319
 
1297
1320
  def _mask_tokens_in_url(url)
1298
1321
  url.gsub(/token=([^&]{10})[^&]*/, 'token=\1...')
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PostHog
4
- VERSION = '3.14.2'
4
+ VERSION = '3.14.3'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: posthog-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.14.2
4
+ version: 3.14.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''