Skip to content

EG-4662 (12): Share _InstanceRegistry using a singleton - #423

Merged
ppicom merged 12 commits into
mainfrom
eg-4662-12-instance-registry
Sep 25, 2026
Merged

ppicom merged 12 commits into
mainfrom
eg-4662-12-instance-registry

Conversation

@ppicom

@ppicom ppicom commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

Part of what the SDK does is registering how many copies of a client you've got running. There's different modes in which this can run:

  1. We don't let you run more than one copy
  2. We warn you
  3. We do nothing (and let you do whatever you want)

The changes in this PR move the logic of registering an SDK as "in use" to a new InstanceRegistry class. SDKs will use it as a singleton so that there is only one count of connected SDKs per runtime, regardless of what combination of SDKs the user decides to use.

NOTE: The original client did not de-register clients, which is something that the Copilot review has brought up. I'd leave it as a possible improvement after an initial review because I don't see it as a big issue. But I'm open to feedback on that as well.

  • feat: move instance registration out of utils and make it a singleton
  • refactor: replace InstanceCounter in UnleashClient by InstanceRegistry singleton
  • feat: wire async client with InstanceRegistry
  • docs: tentative changelog update

@ppicom ppicom changed the title eg 4662 12 instance registry EG-4662 (12): Share InstanceRegistry using a singleton Aug 20, 2026
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch from 0e1732e to 4d52383 Compare August 20, 2026 06:56
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch 2 times, most recently from 5aff4c5 to 7624b9d Compare August 20, 2026 07:29
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch 2 times, most recently from a7a3450 to fa31283 Compare August 20, 2026 07:38
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch from fa31283 to 05010c3 Compare August 20, 2026 08:26
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch from 5b09f3b to aad3ead Compare August 20, 2026 09:21
@gastonfournier gastonfournier moved this from New to In Progress in Issues and PRs Aug 21, 2026
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch from aad3ead to a3ac936 Compare August 21, 2026 08:59
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch from a3ac936 to afb7f7b Compare August 21, 2026 09:44
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch from afb7f7b to bb76cf0 Compare September 21, 2026 13:33
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch from bb76cf0 to d40073d Compare September 21, 2026 14:28
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch 2 times, most recently from 1317629 to 51cc048 Compare September 23, 2026 06:45
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch from b86cb9e to 779e820 Compare September 24, 2026 09:52
Base automatically changed from eg-4662-11-async-metrics-reporter to main September 24, 2026 12:58
@ppicom
ppicom force-pushed the eg-4662-12-instance-registry branch from 779e820 to 063acbf Compare September 24, 2026 12:58
@ppicom ppicom changed the title EG-4662 (12): Share InstanceRegistry using a singleton EG-4662 (12): Share _InstanceRegistry using a singleton Sep 25, 2026
@ppicom
ppicom requested review from alexanto and a lite review from Copilot September 25, 2026 07:30

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Resolve the critical async registration and positional API compatibility issues before approval.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 High severity · 1 Medium severity · 1 Low severity

Open (4)
What changed in this PR

Moves duplicate-instance tracking into a shared singleton registry for synchronous and asynchronous clients.

Changes:

  • Replaces InstanceCounter with _InstanceRegistry.
  • Adds async-client registration and duplicate-instance modes.
  • Updates tests and changelog documentation.
File Summary
UnleashClient/​utils.py Removes the old instance counter.
UnleashClient/​clients/​unleash_client.py Uses the shared registry for synchronous clients.
UnleashClient/​clients/​async_unleash_client.py Adds async registration; critical issues remain around unfinished lifecycle methods and positional API compatibility (1 and 2 votes).
UnleashClient/​_instance_registry.py Implements the singleton registry; entries are never removed after client destruction (moderate, 2 votes).
tests/​unit_tests/​test_instance_registry.py Tests registry behavior and singleton identity.
tests/​unit_tests/​clients/​test_async_unleash_client.py Tests async duplicate-instance behavior.
CHANGELOG.md Documents the changes; the async behavior description is inaccurate (nit, 2 votes).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread UnleashClient/clients/async_unleash_client.py
Comment on lines +94 to +96
_get_instance().register(
identifier=self._config.instance_identifier, mode=multiple_instance_mode
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Valid point, registration should happen at initialization.

Comment thread UnleashClient/_instance_registry.py
Comment thread CHANGELOG.md
Comment thread UnleashClient/_instance_registry.py Outdated
Comment thread UnleashClient/_instance_registry.py Outdated
Comment thread UnleashClient/_instance_registry.py Outdated
Comment thread UnleashClient/_instance_registry.py Outdated
Comment thread UnleashClient/_instance_registry.py Outdated
Comment thread UnleashClient/clients/unleash_client.py Outdated
self._closed = threading.Event()

self._do_instance_check(multiple_instance_mode)
_get_instance().register(

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.

Suggested change
_get_instance().register(
INSTANCES.register(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The idea is that using _get_instance() left the door open to lazy initialization, but I did not implement it. 🤔 I think I prefer to leave the function in place for the moment. Sounds right?

Comment thread CHANGELOG.md Outdated
* (Minor): The Sphinx documentation site is no longer built or published. It was served from a GitHub Pages custom domain that stopped resolving, so nothing published there had been reachable for some time. Reference documentation for this SDK is at https://docs.getunleash.io/reference/sdks/python, and `README.md` covers installation, usage, configuration options, custom strategies, custom caches, event callbacks and the WSGI and Celery notes. Contributor setup and the release checklist are in `DEVELOPMENT.md`. The `Documentation` URL in the package metadata now points at the docs site rather than a page that returned 404.
* (Minor): `AsyncUnleashClient` ignores `custom_options`. The constructor still accepts it and it still reaches the shared configuration, but the async request path never passes it to the HTTP library, so the async client's surface does not depend on aiohttp's own keyword arguments. `UnleashClient` is unaffected and keeps passing `custom_options` to `requests`.
* (Minor): The in-progress asynchronous client now builds an `AsyncMetricsReporter` over its `AsyncTransport`, and exposes `impact_metrics` like the synchronous client does. Nothing starts it yet — `initialize_client()` still raises `NotImplementedError` — so no metrics are sent, and nothing changes for code using `UnleashClient`. The request body, the impact-metrics collection and the restore-after-a-failed-send are shared with the synchronous reporter; only the request itself and the recurring schedule are separate.
* (Minor): Duplicate-instance detection now happens through one internal `_InstanceRegistry`, in the private `UnleashClient._instance_registry` module, instead of an `InstanceCounter` and a private method on the client. The identifier a client is keyed by, the message, the exception raised under `InstanceAllowType.BLOCK`, the error logged under `InstanceAllowType.WARN` and the counting are exactly what they were, and a client rejected under `BLOCK` is still not counted. `INSTANCES` keeps its name, both its import paths and all of its methods, and remains the supported way to reach the registry. The module is not part of the public API and may change or disappear without notice. `multiple_instance_mode` is unchanged. `UnleashClient.utils.InstanceCounter` is gone, so this affects code importing that class directly. Nothing changes for code using `UnleashClient`.

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.

should we be referencing internal modules in the changelog? 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Uhmm right now the change log is generated, but it's not final. I am using it so we can later decide what goes into the final changelog + the docs.

But I'm open to better ways to do this 👍

@sighphyre sighphyre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@ppicom
ppicom merged commit cb28e83 into main Sep 25, 2026
8 checks passed
@ppicom
ppicom deleted the eg-4662-12-instance-registry branch September 25, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

7 participants