Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/tidy-mcp-lifecycle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"posthog-ruby": patch
---

Fix instance tracking for client subclasses so `PostHog::MCP::Client` can initialize outside test mode and shut down without raising. Clients that skip registration no longer remove another client's duplicate-instance warning on shutdown.
5 changes: 3 additions & 2 deletions lib/posthog/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ def initialize(opts = {})

# Warn when multiple clients are created with the same API key (can cause dropped events)
unless @disabled || opts[:test_mode] || opts[:disable_singleton_warning]
previous_count = self.class._increment_instance_count(@api_key)
previous_count = PostHog::Client._increment_instance_count(@api_key)
@instance_registered = true
if previous_count >= 1
logger.warn(
'Multiple PostHog client instances detected for the same API key. ' \
Expand Down Expand Up @@ -947,7 +948,7 @@ def shutdown(timeout: nil)

flushed = false
begin
self.class._decrement_instance_count(@api_key) unless @disabled
PostHog::Client._decrement_instance_count(@api_key) if @instance_registered
@feature_flags_poller&.shutdown_poller
flushed =
if @sync_mode
Expand Down
39 changes: 39 additions & 0 deletions spec/posthog/mcp/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,45 @@
require_relative 'spec_helper'

RSpec.describe PostHog::MCP::Client do
describe 'lifecycle' do
[PostHog::Client, described_class].each do |client_class|
[{ test_mode: true }, { disable_singleton_warning: true }].each do |options|
it "preserves live-client warnings after #{client_class} shuts down with #{options.inspect}" do
clients = []
logger = PostHog::Logging.logger
allow(logger).to receive(:warn)
live = PostHog::Client.new(api_key: 'phc_shared_lifecycle')
clients << live
unregistered = client_class.new({ api_key: 'phc_shared_lifecycle' }.merge(options))
clients << unregistered

expect(unregistered.shutdown(timeout: 2)).to be(true)
expect(unregistered.shutdown(timeout: 2)).to be(true)
clients << PostHog::Client.new(api_key: 'phc_shared_lifecycle')
expect(logger).to have_received(:warn).with(a_string_including('Multiple PostHog client instances')).once

clients.each { |instance| instance.shutdown(timeout: 2) }
clients << PostHog::Client.new(api_key: 'phc_shared_lifecycle')
expect(logger).to have_received(:warn).with(a_string_including('Multiple PostHog client instances')).once
ensure
clients.each { |instance| instance.shutdown(timeout: 2) }
end
end
end

[{ test_mode: true }, { sync_mode: true }, {}].each do |options|
it "constructs and shuts down with #{options.inspect}" do
stub_request(:post, 'https://us.i.posthog.com/batch/').to_return(status: 200, body: '{}')
mcp_client = described_class.new({ api_key: 'phc_lifecycle' }.merge(options))
mcp_client.capture_tool_call('echo', distinct_id: 'user')

expect(mcp_client.shutdown(timeout: 2)).to be(true)
expect(mcp_client.shutdown(timeout: 2)).to be(true)
expect(mcp_client.capture(event: 'after shutdown', distinct_id: 'user')).to be(false)
end
end
end

let(:client) { described_class.new(api_key: 'phc_test', test_mode: true) }

it 'captures tool calls with $lib override, anonymous distinct id and error scalars' do
Expand Down
Loading