posthog-ruby 3.19.0 → 3.20.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: b23e0da0723e7582825d0888d8c6ffd9b3ad0a77e5eec513a40ab3de1faaa306
4
- data.tar.gz: 1fc203c912147dc865cb342213ef8ccd3604e4d84f0b0005932c559aa30c8017
3
+ metadata.gz: 36dffe9438cc269541f1642261b27b020bf05993eda1ad9999887428caa1667b
4
+ data.tar.gz: 9575ff454af5b89c0be1eb6abf4c7a1158fdbca88d4c708860339a1710b1393d
5
5
  SHA512:
6
- metadata.gz: 8409ba6d5fb0801643cbd6556a1dabf41441ff522b85d612601ac8547482c5eb139ac68f21250f2f240654f08c03b3ca6cdc0409f57f1c6af9cdd880c677805f
7
- data.tar.gz: c7a146c293985480777e6f5139588ca0d897170b8fe15412e9d60561711cb57bec53e70225b8b209916a50835f249b9816bece364be754a56e6f1118454feb52
6
+ metadata.gz: 9badf7f03c2009d4c643b6e41f4ede382c0bf488eb0ae4d5cf33ec454110102e3fc342b5f3357b58b881f2a513628ba6056f0ccfa82d54ac8cafb4d814ae3811
7
+ data.tar.gz: e7918e45f9645da0052d65d205359e8384709f645f0f1b5201500a5cc97bb092aed771cd7fac7846f5bfc142fcb9e8168f55d9cbc750c6bbb8aab26e60e1138d
@@ -76,6 +76,13 @@ module PostHog
76
76
  # @option opts [Integer] :feature_flag_request_max_retries How many times to retry a flag request after a
77
77
  # transient network error. Each retry sleeps on the calling thread before retrying, so this adds to
78
78
  # worst-case latency. Defaults to 1. Set to 0 to disable retrying.
79
+ # @option opts [Boolean] :feature_flags_async_load +true+ to fetch feature flag definitions for local
80
+ # evaluation only on the poller's background thread instead of the calling thread. The constructor
81
+ # returns without waiting for definitions: the poller fetches immediately on boot and, if that fails,
82
+ # keeps retrying on its regular polling interval until a load succeeds. Until then local evaluation
83
+ # treats definitions as absent (check {#feature_flags_loaded?}), so evaluations return nil with
84
+ # +only_evaluate_locally: true+, or fall back to the remote flags endpoint (which still runs on the
85
+ # calling thread) without it. Defaults to +false+.
79
86
  # @option opts [Proc] :before_send A callback that receives the event hash and should return either a modified
80
87
  # hash to be sent to PostHog or nil to prevent the event from being sent. e.g. `before_send: ->(event) { event }`.
81
88
  # @option opts [Boolean] :disable_singleton_warning +true+ to suppress the warning when multiple clients share
@@ -162,7 +169,8 @@ module PostHog
162
169
  opts[:feature_flag_request_timeout_seconds] || Defaults::FeatureFlags::FLAG_REQUEST_TIMEOUT_SECONDS,
163
170
  opts[:on_error],
164
171
  flag_definition_cache_provider: opts[:flag_definition_cache_provider],
165
- feature_flag_request_max_retries: opts[:feature_flag_request_max_retries]
172
+ feature_flag_request_max_retries: opts[:feature_flag_request_max_retries],
173
+ async_load: opts[:feature_flags_async_load] == true
166
174
  )
167
175
  end
168
176
 
@@ -772,7 +780,8 @@ module PostHog
772
780
  response
773
781
  end
774
782
 
775
- # Reload locally cached feature flag definitions.
783
+ # Reload locally cached feature flag definitions synchronously on the
784
+ # calling thread.
776
785
  #
777
786
  # @return [void]
778
787
  def reload_feature_flags
@@ -787,6 +796,17 @@ module PostHog
787
796
  @feature_flags_poller.load_feature_flags(true)
788
797
  end
789
798
 
799
+ # Whether feature flag definitions for local evaluation are currently loaded.
800
+ # False until the first successful load, and false again if a quota-limited
801
+ # (402) response discards the definitions.
802
+ #
803
+ # @return [Boolean]
804
+ def feature_flags_loaded?
805
+ return false if @disabled
806
+
807
+ @feature_flags_poller.definitions_loaded?
808
+ end
809
+
790
810
  # Whether the client will actually send events. It is disabled when the
791
811
  # api_key is missing or blank, in which case every capture call no-ops.
792
812
  #
@@ -19,6 +19,7 @@ module PostHog
19
19
 
20
20
  module FeatureFlags
21
21
  FLAG_REQUEST_TIMEOUT_SECONDS = 3
22
+ POLLING_INTERVAL_SECONDS = 30
22
23
  # Number of retries for a flag request after a transient network error.
23
24
  # Flag requests are stateless and cause no server-side mutation, so
24
25
  # retrying is safe.
@@ -30,6 +30,7 @@ module PostHog
30
30
  include PostHog::Utils
31
31
 
32
32
  # @param polling_interval [Integer, nil] Seconds between local feature flag definition polls.
33
+ # Defaults to {Defaults::FeatureFlags::POLLING_INTERVAL_SECONDS}.
33
34
  # @param secret_key [String, nil] Credential used to fetch local evaluation definitions. Accepts either a
34
35
  # Personal API Key (`phx_...`) or a Project Secret API Key (`phs_...`).
35
36
  # @param project_api_key [String] Project API key.
@@ -40,6 +41,9 @@ module PostHog
40
41
  # @param feature_flag_request_max_retries [Integer, nil] Retries after a transient network error or retryable
41
42
  # HTTP response status on a flag request. Defaults to {Defaults::FeatureFlags::FLAG_REQUEST_MAX_RETRIES}.
42
43
  # Set to 0 to disable retrying.
44
+ # @param async_load [Boolean] When true, flag definitions are fetched only on the poller thread: an
45
+ # immediate first tick at construction, then the regular polling cadence, which keeps retrying until a
46
+ # load succeeds.
43
47
  def initialize(
44
48
  polling_interval,
45
49
  secret_key,
@@ -48,9 +52,10 @@ module PostHog
48
52
  feature_flag_request_timeout_seconds,
49
53
  on_error = nil,
50
54
  flag_definition_cache_provider: nil,
51
- feature_flag_request_max_retries: nil
55
+ feature_flag_request_max_retries: nil,
56
+ async_load: false
52
57
  )
53
- @polling_interval = polling_interval || 30
58
+ @polling_interval = polling_interval || Defaults::FeatureFlags::POLLING_INTERVAL_SECONDS
54
59
  @secret_key = secret_key
55
60
  @project_api_key = project_api_key
56
61
  @host = host
@@ -65,14 +70,16 @@ module PostHog
65
70
  @on_error = on_error || proc { |status, error| }
66
71
  @quota_limited = Concurrent::AtomicBoolean.new(false)
67
72
  @flags_etag = Concurrent::AtomicReference.new(nil)
68
- @flag_definitions_loaded_at = nil
73
+ @flag_definitions_loaded_at = Concurrent::AtomicReference.new(nil)
74
+ @async_load = async_load
69
75
 
70
76
  @flag_definition_cache_provider = flag_definition_cache_provider
71
77
  FlagDefinitionCacheProvider.validate!(@flag_definition_cache_provider) if @flag_definition_cache_provider
72
78
 
73
79
  @task =
74
80
  Concurrent::TimerTask.new(
75
- execution_interval: polling_interval
81
+ execution_interval: @polling_interval,
82
+ run_now: @async_load
76
83
  ) { _load_feature_flags }
77
84
 
78
85
  # If no secret_key, disable local evaluation & thus polling for definitions
@@ -80,19 +87,31 @@ module PostHog
80
87
  logger.info 'No secret_key provided, disabling local evaluation'
81
88
  @loaded_flags_successfully_once.make_true
82
89
  else
83
- # load once before timer
84
- load_feature_flags
90
+ # load once synchronously before timer, unless @async_load
91
+ load_feature_flags unless @async_load
85
92
  @task.execute
86
93
  end
87
94
  end
88
95
 
89
96
  def load_feature_flags(force_reload = false)
90
- return unless @loaded_flags_successfully_once.false? || force_reload
97
+ return if (@loaded_flags_successfully_once.true? || @async_load) && !force_reload
91
98
 
92
99
  _load_feature_flags
93
100
  end
94
101
 
95
- attr_reader :flag_definitions_loaded_at, :feature_flags_by_key
102
+ # Whether flag definitions are currently loaded. False until the first
103
+ # successful load, and false again if a quota-limited (402) response
104
+ # discards them.
105
+ def definitions_loaded?
106
+ !@flag_definitions_loaded_at.value.nil?
107
+ end
108
+
109
+ # Epoch milliseconds of the last successful definitions load, or nil.
110
+ def flag_definitions_loaded_at
111
+ @flag_definitions_loaded_at.value
112
+ end
113
+
114
+ attr_reader :feature_flags_by_key
96
115
 
97
116
  def get_feature_variants(
98
117
  distinct_id,
@@ -1183,6 +1202,7 @@ module PostHog
1183
1202
  @feature_flags_by_key = {}
1184
1203
  @group_type_mapping = Concurrent::Hash.new
1185
1204
  @cohorts = Concurrent::Hash.new
1205
+ @flag_definitions_loaded_at.value = nil
1186
1206
  @loaded_flags_successfully_once.make_false
1187
1207
  @quota_limited.make_true
1188
1208
  return
@@ -1231,7 +1251,7 @@ module PostHog
1231
1251
  @cohorts = Concurrent::Hash[deep_symbolize_keys(cohorts)]
1232
1252
 
1233
1253
  logger.debug "Loaded #{@feature_flags.length} feature flags and #{@cohorts.length} cohorts"
1234
- @flag_definitions_loaded_at = (Time.now.to_f * 1000).to_i
1254
+ @flag_definitions_loaded_at.value = (Time.now.to_f * 1000).to_i
1235
1255
  @loaded_flags_successfully_once.make_true if @loaded_flags_successfully_once.false?
1236
1256
  end
1237
1257
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PostHog
4
- VERSION = '3.19.0'
4
+ VERSION = '3.20.0'
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.19.0
4
+ version: 3.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''