Skip to content

fix: use shared instance tracking for MCP clients - #284

Merged
marandaneto merged 2 commits into
mainfrom
fix/mcp-client-lifecycle
Sep 29, 2026
Merged

marandaneto merged 2 commits into
mainfrom
fix/mcp-client-lifecycle

Conversation

@marandaneto

@marandaneto marandaneto commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

💡 Motivation and Context

PostHog::MCP::Client inherits the client instance-tracking methods, but Ruby class-instance variables are not inherited. Calling those methods on the subclass accesses a nil mutex and raises NoMethodError during normal initialization. Test-mode initialization skips registration but encounters the same problem during shutdown.

Use the registry owned by PostHog::Client for both registration and removal. Record whether each instance registered, and only decrement its count if it did. Shutting down a test-mode client or a client with singleton warnings disabled must not remove another live client's registration.

Add lifecycle regression tests for test, synchronous, and asynchronous clients, mixed-client warning preservation, and a patch changeset.

This extracts the production fix from #283 so it can merge separately. Once this merges, syncing #283 with main will remove these changes from its diff.

💚 How did you test it?

  • All three lifecycle cases fail against the unchanged production code and pass with the fix.
  • Four mixed-client cases fail before the registration guard and pass afterward. They cover core and MCP clients with test mode or singleton warnings disabled, repeated shutdown, and removal of registered clients.
  • The full default suite passes with 1,226 examples and zero failures on Ruby 4.0.7.
  • RuboCop passes for both changed Ruby files. The public API snapshot check and git diff --check pass.
  • Autoreview of b728ad1 against origin/main reports no actionable findings.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

The patch changeset was written directly in the repository's changeset format. No documentation or public API changes are needed.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Pi used file and shell tools to extract the fix into a new worktree based on main, reproduce the failures, and validate the patch. The autoreview helper reviewed the final commit. Only the production fix, its regression tests, and its changeset are included. Human review is required.

@marandaneto marandaneto self-assigned this Sep 27, 2026
@marandaneto
marandaneto marked this pull request as ready for review September 27, 2026 09:20
@marandaneto
marandaneto requested a review from a team as a code owner September 27, 2026 09:20
@marandaneto
marandaneto requested a review from a team September 27, 2026 09:21
@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

posthog-ruby-async Compliance Report

Date: 2026-09-27T13:22:50.184349+00:00
Duration: 98217ms

⚠️ Some Tests Failed

46/47 tests passed, 1 failed


Capture Tests

✅ 30/30 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 110ms
Format Validation.Event Has Uuid ✅ 107ms
Format Validation.Event Has Lib Properties ✅ 109ms
Format Validation.Distinct Id Is String ✅ 107ms
Format Validation.Token Is Present ✅ 108ms
Format Validation.Custom Properties Preserved ✅ 107ms
Format Validation.Event Has Timestamp ✅ 107ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 10ms
Retry Behavior.Retries On 503 ✅ 5311ms
Retry Behavior.Does Not Retry On 400 ✅ 2109ms
Retry Behavior.Does Not Retry On 401 ✅ 2109ms
Retry Behavior.Respects Retry After Header ✅ 8014ms
Retry Behavior.Implements Backoff ✅ 15624ms
Retry Behavior.Retries On 500 ✅ 5212ms
Retry Behavior.Retries On 502 ✅ 5212ms
Retry Behavior.Retries On 504 ✅ 5212ms
Retry Behavior.Max Retries Respected ✅ 15523ms
Deduplication.Generates Unique Uuids ✅ 112ms
Deduplication.Preserves Uuid On Retry ✅ 5213ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10312ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5214ms
Deduplication.No Duplicate Events In Batch ✅ 112ms
Deduplication.Different Events Have Different Uuids ✅ 107ms
Compression.Sends Gzip When Enabled ✅ 107ms
Batch Format.Uses Proper Batch Structure ✅ 106ms
Batch Format.Flush With No Events Sends Nothing ✅ 5ms
Batch Format.Multiple Events Batched Together ✅ 110ms
Error Handling.Does Not Retry On 403 ✅ 2108ms
Error Handling.Does Not Retry On 413 ✅ 2109ms
Error Handling.Retries On 408 ✅ 5212ms

Feature_Flags Tests

⚠️ 16/17 tests passed, 1 failed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 108ms
Request Payload.Flags Request Uses V2 Query Param ✅ 108ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 109ms
Request Payload.Flags Request Omits Authorization Header ✅ 109ms
Request Payload.Token In Flags Body Matches Init ✅ 107ms
Request Payload.Groups Round Trip ✅ 108ms
Request Payload.Groups Default To Empty Object ✅ 107ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 107ms
Request Payload.Disable Geoip Omitted Defaults To False ❌ 107ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 107ms
Request Lifecycle.No Flags Request On Init Alone ✅ 4ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 105ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 113ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 106ms
Retry Behavior.Retries Flags On 502 ✅ 257ms
Retry Behavior.Retries Flags On 504 ✅ 241ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 109ms

Failures

request_payload.disable_geoip_omitted_defaults_to_false

Field 'geoip_disable' not found in /flags request body at path 'geoip_disable'. Available keys: ['distinct_id', 'groups', 'person_properties', 'group_properties', 'flag_keys_to_evaluate', 'token']

@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

posthog-ruby-sync Compliance Report

Date: 2026-09-27T13:23:12.357206+00:00
Duration: 94133ms

⚠️ Some Tests Failed

45/47 tests passed, 2 failed


Capture Tests

⚠️ 29/30 tests passed, 1 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 10ms
Format Validation.Event Has Uuid ✅ 6ms
Format Validation.Event Has Lib Properties ✅ 6ms
Format Validation.Distinct Id Is String ✅ 9ms
Format Validation.Token Is Present ✅ 8ms
Format Validation.Custom Properties Preserved ✅ 6ms
Format Validation.Event Has Timestamp ✅ 8ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 7ms
Retry Behavior.Retries On 503 ✅ 5275ms
Retry Behavior.Does Not Retry On 400 ✅ 2010ms
Retry Behavior.Does Not Retry On 401 ✅ 2011ms
Retry Behavior.Respects Retry After Header ✅ 8016ms
Retry Behavior.Implements Backoff ✅ 15376ms
Retry Behavior.Retries On 500 ✅ 5114ms
Retry Behavior.Retries On 502 ✅ 5116ms
Retry Behavior.Retries On 504 ✅ 5115ms
Retry Behavior.Max Retries Respected ✅ 15484ms
Deduplication.Generates Unique Uuids ✅ 21ms
Deduplication.Preserves Uuid On Retry ✅ 5113ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10323ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5157ms
Deduplication.No Duplicate Events In Batch ✅ 18ms
Deduplication.Different Events Have Different Uuids ✅ 9ms
Compression.Sends Gzip When Enabled ✅ 7ms
Batch Format.Uses Proper Batch Structure ✅ 6ms
Batch Format.Flush With No Events Sends Nothing ✅ 3ms
Batch Format.Multiple Events Batched Together ❌ 18ms
Error Handling.Does Not Retry On 403 ✅ 2008ms
Error Handling.Does Not Retry On 413 ✅ 2010ms
Error Handling.Retries On 408 ✅ 5153ms

Failures

batch_format.multiple_events_batched_together

Expected 1 requests, got 5

Feature_Flags Tests

⚠️ 16/17 tests passed, 1 failed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 8ms
Request Payload.Flags Request Uses V2 Query Param ✅ 7ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 6ms
Request Payload.Flags Request Omits Authorization Header ✅ 7ms
Request Payload.Token In Flags Body Matches Init ✅ 7ms
Request Payload.Groups Round Trip ✅ 8ms
Request Payload.Groups Default To Empty Object ✅ 8ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 7ms
Request Payload.Disable Geoip Omitted Defaults To False ❌ 9ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 6ms
Request Lifecycle.No Flags Request On Init Alone ✅ 3ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 6ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 8ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 7ms
Retry Behavior.Retries Flags On 502 ✅ 143ms
Retry Behavior.Retries Flags On 504 ✅ 151ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 8ms

Failures

request_payload.disable_geoip_omitted_defaults_to_false

Field 'geoip_disable' not found in /flags request body at path 'geoip_disable'. Available keys: ['distinct_id', 'groups', 'person_properties', 'group_properties', 'flag_keys_to_evaluate', 'token']

@greptile-apps

greptile-apps Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[Medium risk] Changes instance tracking for client subclasses.

The PR is not safe to merge until shutdown preserves the registration of a live client sharing the API key.

Reviews (1) · Last reviewed commit: "fix: use shared instance tracking for MC..."

Comment thread lib/posthog/client.rb Outdated
@marandaneto marandaneto mentioned this pull request Sep 28, 2026
4 of 5 tasks

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed b728ad1d2118b6492cfc3caeb6f7ffd8efae5b37. No blocking code findings.

The per-instance registration guard correctly protects shared consumer lifetime, including mixed-client shutdown. The previous unregistered-client concern is addressed. Ruby 3.2–3.4 checks pass; advisory compliance reports still contain geoip/batching failures, so this is not a full-conformance claim.

AI-assisted review of the diff, affected callers/tests, and existing CI. No tests were run locally.

@marandaneto
marandaneto merged commit 161de85 into main Sep 29, 2026
22 of 23 checks passed
@marandaneto
marandaneto deleted the fix/mcp-client-lifecycle branch September 29, 2026 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants