Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 33 additions & 17 deletions lib/posthog/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ def initialize(opts = {})

@queue = Queue.new
@api_key = opts[:api_key]
@disabled = @api_key.nil? || (@api_key.respond_to?(:empty?) && @api_key.empty?)
@max_queue_size = opts[:max_queue_size] || Defaults::Queue::MAX_SIZE
@worker_mutex = Mutex.new
@sync_mode = opts[:sync_mode] == true && !opts[:test_mode]
@sync_mode = opts[:sync_mode] == true && !opts[:test_mode] && !@disabled
@on_error = opts[:on_error] || proc { |status, error| }
@worker = if opts[:test_mode]
@worker = if opts[:test_mode] || @disabled
NoopWorker.new(@queue)
elsif @sync_mode
nil
Expand All @@ -103,11 +104,10 @@ def initialize(opts = {})
@feature_flags_poller = nil
@personal_api_key = opts[:personal_api_key]

check_api_key!
logger.error('api_key is empty after trimming whitespace; check your project API key') if @api_key == ''

# Warn when multiple clients are created with the same API key (can cause dropped events)
unless opts[:test_mode] || opts[:disable_singleton_warning]
unless @disabled || opts[:test_mode] || opts[:disable_singleton_warning]
previous_count = self.class._increment_instance_count(@api_key)
if previous_count >= 1
logger.warn(
Expand All @@ -119,16 +119,18 @@ def initialize(opts = {})
end
end

@feature_flags_poller =
FeatureFlagsPoller.new(
opts[:feature_flags_polling_interval],
opts[:personal_api_key],
@api_key,
opts[:host],
opts[:feature_flag_request_timeout_seconds] || Defaults::FeatureFlags::FLAG_REQUEST_TIMEOUT_SECONDS,
opts[:on_error],
flag_definition_cache_provider: opts[:flag_definition_cache_provider]
)
unless @disabled
@feature_flags_poller =
FeatureFlagsPoller.new(
opts[:feature_flags_polling_interval],
opts[:personal_api_key],
@api_key,
opts[:host],
opts[:feature_flag_request_timeout_seconds] || Defaults::FeatureFlags::FLAG_REQUEST_TIMEOUT_SECONDS,
opts[:on_error],
flag_definition_cache_provider: opts[:flag_definition_cache_provider]
)
end

@distinct_id_has_sent_flag_calls = SizeLimitedHash.new(Defaults::MAX_HASH_SIZE) do |hash, key|
hash[key] = []
Expand Down Expand Up @@ -184,7 +186,7 @@ def capture(attrs)
symbolize_keys! attrs

send_feature_flags_param = attrs[:send_feature_flags]
if send_feature_flags_param
if send_feature_flags_param && !@disabled
# Handle different types of send_feature_flags parameter
case send_feature_flags_param
when true
Expand Down Expand Up @@ -320,6 +322,8 @@ def is_feature_enabled( # rubocop:disable Naming/PredicateName
# @param [String] flag_key The unique flag key of the feature flag
# @return [String] The decrypted value of the feature flag payload
def get_remote_config_payload(flag_key)
return nil if @disabled

@feature_flags_poller.get_remote_config_payload(flag_key)
end

Expand Down Expand Up @@ -387,6 +391,8 @@ def get_feature_flag_result(
only_evaluate_locally: false,
send_feature_flag_events: true
)
return nil if @disabled

person_properties, group_properties = add_local_person_and_group_properties(
distinct_id,
groups,
Expand Down Expand Up @@ -441,6 +447,8 @@ def get_all_flags(
group_properties: {},
only_evaluate_locally: false
)
return {} if @disabled

person_properties, group_properties = add_local_person_and_group_properties(distinct_id, groups,
person_properties, group_properties)
@feature_flags_poller.get_all_flags(distinct_id, groups, person_properties, group_properties,
Expand Down Expand Up @@ -469,6 +477,8 @@ def get_feature_flag_payload(
group_properties: {},
only_evaluate_locally: false
)
return nil if @disabled

person_properties, group_properties = add_local_person_and_group_properties(distinct_id, groups,
person_properties, group_properties)
@feature_flags_poller.get_feature_flag_payload(key, distinct_id, match_value, groups, person_properties,
Expand All @@ -494,6 +504,8 @@ def get_all_flags_and_payloads(
group_properties: {},
only_evaluate_locally: false
)
return { featureFlags: {}, featureFlagPayloads: {} } if @disabled

person_properties, group_properties = add_local_person_and_group_properties(
distinct_id, groups, person_properties, group_properties
)
Expand All @@ -508,6 +520,8 @@ def get_all_flags_and_payloads(
end

def reload_feature_flags
return if @disabled

unless @personal_api_key
logger.error(
'You need to specify a personal_api_key to locally evaluate feature flags'
Expand All @@ -518,8 +532,8 @@ def reload_feature_flags
end

def shutdown
self.class._decrement_instance_count(@api_key) if @api_key
@feature_flags_poller.shutdown_poller
self.class._decrement_instance_count(@api_key) unless @disabled
@feature_flags_poller&.shutdown_poller
flush
if @sync_mode
@sync_lock.synchronize { @transport&.shutdown }
Expand Down Expand Up @@ -557,6 +571,8 @@ def process_before_send(action)
#
# returns Boolean of whether the item was added to the queue.
def enqueue(action)
return false if @disabled

action = process_before_send(action)
return false if action.nil? || action.empty?

Expand Down
29 changes: 27 additions & 2 deletions spec/posthog/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,33 @@ module PostHog
end

describe '#initialize' do
it 'errors if no api_key is supplied' do
expect { Client.new }.to raise_error(ArgumentError)
it 'creates a disabled client if no api_key is supplied' do
client = nil

expect { client = Client.new }.to_not raise_error

expect(client.instance_variable_get(:@disabled)).to eq(true)
expect(client.instance_variable_get(:@worker)).to be_a(PostHog::NoopWorker)
end

it 'creates a disabled client if api_key is nil, empty, or blank after trimming' do
[{ api_key: nil }, { api_key: '' }, { api_key: " \n\t " }].each do |opts|
client = Client.new(opts)

expect(client.instance_variable_get(:@disabled)).to eq(true)
expect(client.instance_variable_get(:@worker)).to be_a(PostHog::NoopWorker)
expect(client.capture(Queued::CAPTURE)).to eq(false)
expect(client.queued_messages).to eq(0)
end
end

it 'does not start a sender or sync transport when api_key is nil, empty, or blank after trimming' do
expect(PostHog::SendWorker).not_to receive(:new)
expect(PostHog::Transport).not_to receive(:new)

[nil, '', " \n\t "].each do |api_key|
Client.new(api_key: api_key, sync_mode: true)
end
end

it 'does not error if a api_key is supplied' do
Expand Down
Loading