From 8a0509b8795f471527bf5831f6b3d9ddc7d9530f Mon Sep 17 00:00:00 2001 From: Felix Livni Date: Fri, 17 Jul 2026 00:58:37 -0700 Subject: [PATCH 1/2] fix(flags): pass the resolved polling interval to the definitions poll timer --- .changeset/polling-interval-default.md | 5 +++++ lib/posthog/defaults.rb | 1 + lib/posthog/feature_flags.rb | 5 +++-- public_api_snapshot.txt | 1 + spec/posthog/feature_flag_spec.rb | 29 ++++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 .changeset/polling-interval-default.md diff --git a/.changeset/polling-interval-default.md b/.changeset/polling-interval-default.md new file mode 100644 index 0000000..0a64e8c --- /dev/null +++ b/.changeset/polling-interval-default.md @@ -0,0 +1,5 @@ +--- +"posthog-ruby": patch +--- + +fix: honor the documented 30s default for `feature_flags_polling_interval`. The resolved default was computed but never passed to the polling timer, so when the option was unset the effective interval was concurrent-ruby's 60s TimerTask default. Definitions now poll every 30s by default as documented; set `feature_flags_polling_interval: 60` to keep the previous effective cadence. diff --git a/lib/posthog/defaults.rb b/lib/posthog/defaults.rb index eea7666..d152ec4 100644 --- a/lib/posthog/defaults.rb +++ b/lib/posthog/defaults.rb @@ -19,6 +19,7 @@ module Request module FeatureFlags FLAG_REQUEST_TIMEOUT_SECONDS = 3 + POLLING_INTERVAL_SECONDS = 30 # Number of retries for a flag request after a transient network error. # Flag requests are stateless and cause no server-side mutation, so # retrying is safe. diff --git a/lib/posthog/feature_flags.rb b/lib/posthog/feature_flags.rb index dde847c..159035c 100644 --- a/lib/posthog/feature_flags.rb +++ b/lib/posthog/feature_flags.rb @@ -30,6 +30,7 @@ class FeatureFlagsPoller include PostHog::Utils # @param polling_interval [Integer, nil] Seconds between local feature flag definition polls. + # Defaults to {Defaults::FeatureFlags::POLLING_INTERVAL_SECONDS}. # @param secret_key [String, nil] Credential used to fetch local evaluation definitions. Accepts either a # Personal API Key (`phx_...`) or a Project Secret API Key (`phs_...`). # @param project_api_key [String] Project API key. @@ -50,7 +51,7 @@ def initialize( flag_definition_cache_provider: nil, feature_flag_request_max_retries: nil ) - @polling_interval = polling_interval || 30 + @polling_interval = polling_interval || Defaults::FeatureFlags::POLLING_INTERVAL_SECONDS @secret_key = secret_key @project_api_key = project_api_key @host = host @@ -72,7 +73,7 @@ def initialize( @task = Concurrent::TimerTask.new( - execution_interval: polling_interval + execution_interval: @polling_interval ) { _load_feature_flags } # If no secret_key, disable local evaluation & thus polling for definitions diff --git a/public_api_snapshot.txt b/public_api_snapshot.txt index fb26974..3fb6568 100644 --- a/public_api_snapshot.txt +++ b/public_api_snapshot.txt @@ -36,6 +36,7 @@ constant PostHog::Defaults::BackoffPolicy::RANDOMIZATION_FACTOR: Float module PostHog::Defaults::FeatureFlags constant PostHog::Defaults::FeatureFlags::FLAG_REQUEST_MAX_RETRIES: Integer constant PostHog::Defaults::FeatureFlags::FLAG_REQUEST_TIMEOUT_SECONDS: Integer +constant PostHog::Defaults::FeatureFlags::POLLING_INTERVAL_SECONDS: Integer constant PostHog::Defaults::MAX_HASH_SIZE: Integer module PostHog::Defaults::Message constant PostHog::Defaults::Message::MAX_BYTES: Integer diff --git a/spec/posthog/feature_flag_spec.rb b/spec/posthog/feature_flag_spec.rb index 287183c..db188e9 100644 --- a/spec/posthog/feature_flag_spec.rb +++ b/spec/posthog/feature_flag_spec.rb @@ -5349,4 +5349,33 @@ def flag_called_properties(client, key) end end end + + describe 'definitions polling interval' do + before do + stub_request( + :get, + 'https://us.i.posthog.com/flags/definitions?token=testsecret&send_cohorts=true' + ).to_return(status: 200, body: { flags: [] }.to_json) + end + + def timer_task_interval(client) + poller = client.instance_variable_get(:@feature_flags_poller) + poller.instance_variable_get(:@task).execution_interval + end + + it 'defaults to the documented 30 seconds' do + client = Client.new(api_key: API_KEY, secret_key: API_KEY, test_mode: true) + + expect(timer_task_interval(client)).to eq(30) + end + + it 'uses feature_flags_polling_interval when provided' do + client = Client.new( + api_key: API_KEY, secret_key: API_KEY, test_mode: true, + feature_flags_polling_interval: 15 + ) + + expect(timer_task_interval(client)).to eq(15) + end + end end From 887a636ea9cf8c6954e11d7aa66d753530289dfb Mon Sep 17 00:00:00 2001 From: Felix Livni Date: Fri, 17 Jul 2026 12:16:16 -0700 Subject: [PATCH 2/2] Remove fix prefix from changeset --- .changeset/polling-interval-default.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/polling-interval-default.md b/.changeset/polling-interval-default.md index 0a64e8c..85dd020 100644 --- a/.changeset/polling-interval-default.md +++ b/.changeset/polling-interval-default.md @@ -2,4 +2,4 @@ "posthog-ruby": patch --- -fix: honor the documented 30s default for `feature_flags_polling_interval`. The resolved default was computed but never passed to the polling timer, so when the option was unset the effective interval was concurrent-ruby's 60s TimerTask default. Definitions now poll every 30s by default as documented; set `feature_flags_polling_interval: 60` to keep the previous effective cadence. +Honor the documented 30s default for `feature_flags_polling_interval`. The resolved default was computed but never passed to the polling timer, so when the option was unset the effective interval was concurrent-ruby's 60s TimerTask default. Definitions now poll every 30s by default as documented; set `feature_flags_polling_interval: 60` to keep the previous effective cadence.