Skip to content

feat: Add Identify hooks to Client SDK#234

Open
abelonogov-ld wants to merge 24 commits intomainfrom
andrey/client-identify-hook
Open

feat: Add Identify hooks to Client SDK#234
abelonogov-ld wants to merge 24 commits intomainfrom
andrey/client-identify-hook

Conversation

@abelonogov-ld
Copy link
Contributor

@abelonogov-ld abelonogov-ld commented Mar 10, 2026

Requirements

Adds BeforeIdentify / AfterIdentify hook stages to the existing hooks infrastructure, mirroring the evaluation series pattern. Hooks execute in forward order for BeforeIdentify and reverse (LIFO) order for AfterIdentify.
Wraps LdClient.IdentifyAsync with the identify hook series so that configured hooks receive callbacks before and after each identify operation, with IdentifySeriesResult.Completed on success and IdentifySeriesResult.Error on failure.
Threads maxWaitTime from Identify / IdentifyAsync into IdentifySeriesContext.Timeout so hooks have visibility into the caller's timeout configuration.

  • I have added test coverage for new or changed functionality
  • I have followed the repository's pull request submission guidelines
  • I have validated my changes against all supported platform versions
image

Note

Medium Risk
Touches core Identify and initialization paths and adds new async hook execution around them, which could affect context-switch timing and event/connection behavior if misordered or if hooks are slow/faulty.

Overview
Adds a new hook series for identify operations by extending Hook with BeforeIdentify/AfterIdentify and introducing IdentifySeriesContext (includes timeout) plus IdentifySeriesResult (Completed/Error).

Plumbs this through the internal hook executor (IHookExecutor, Executor, NoopExecutor) and updates LdClient startup and Identify/IdentifyAsync flows to run identify operations inside the hook series, ensuring AfterIdentify runs on both success and exceptions while keeping exceptions propagated. Includes comprehensive tests validating ordering (LIFO), data passthrough, logging on hook failures, status reporting, and hook activation during init.

Written by Cursor Bugbot for commit 11b9692. This will update automatically on new commits. Configure here.

…dk-identify

* andrey/clientsdk-plugins-and-hooks:
  address feadback
  remove files
  remove identify

# Conflicts:
#	pkgs/sdk/client/src/Hooks/IdentifySeriesResult.cs
* main:
  chore(main): release LaunchDarkly.ServerSdk.Ai 0.9.3 (#233)
  fix: Make defaultValue optional with a disabled default (#232)
  chore(main): release LaunchDarkly.ClientSdk 5.6.0 (#231)
  feat: Add plugin support to Client SDK (#229)

# Conflicts:
#	pkgs/sdk/client/src/Internal/Hooks/Executor/Executor.cs
- Modified the ILdClient and ILdClientExtensions interfaces to add a maxWaitTime parameter to IdentifyAsync.
- Updated related documentation and references across multiple files to reflect the new method signature.
- Enhanced the Identify method implementation to utilize the updated IdentifyAsync method with the maxWaitTime parameter.
- Introduced IdentifySeries method in the hook executor to manage identify operations with hooks, including error handling and execution order.
…ementation

- Updated the IdentifyAsync method to remove the maxWaitTime parameter from the public interface.
- Adjusted related documentation to reflect the new method signature.
- Ensured internal implementation retains the maxWaitTime parameter for flexibility in asynchronous identification operations.
@abelonogov-ld abelonogov-ld requested a review from a team as a code owner March 10, 2026 23:24
- Updated IdentifySeriesContext to accept TimeSpan instead of int for timeout, improving clarity and flexibility.
- Adjusted IdentifySeries method in Executor to align with the new IdentifySeriesContext signature.
- Modified IdentifySeriesTest to utilize TimeSpan.Zero for timeout, ensuring consistency in test cases.
@tanderson-ld tanderson-ld self-requested a review March 11, 2026 14:55
Copy link
Contributor

Choose a reason for hiding this comment

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

The logic of changing _context and initing with cached data is also part of identify.

The data in the data store is what drives evaluation. An invocation of identify can't switch which context is being used for evaluation until after beforeIdentify hooks are finished.

Have you considered having the hook executor just use the internal identify for simplicity sake?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I used logic from iOS and Android

Copy link
Contributor

Choose a reason for hiding this comment

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

I gotta look again. Will do tomorrow.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

iOS

The whole of identify work is encapsulated in a work item. This guarantees beforeIdentify finishes before beginning to make changes to internal data store.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now it is more like iOS

Copy link
Contributor

@tanderson-ld tanderson-ld Mar 11, 2026

Choose a reason for hiding this comment

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

The identify series is also supposed to be invoked in the init case I believe. Double check me here with the spec.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

async Task StartAsync()
{
await _connectionManager.Start();
await RecordIdentify(_context, TimeSpan.Zero);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be before the connection manager start because the connection manager does work with the identified context. In this order, it is a contradiction from the customer code's perspective. How can something do work with the identified context until after beforeIdentify has finished?

I think this comment applies in other spots.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure and Interesting

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