fix: Report a distinct User-Agent for the async client - #516
Merged
Merged
Conversation
The async client shipped reusing the sync 'PythonClient/<version>' User-Agent, so LaunchDarkly could not tell async traffic apart from sync. Since sync and async ship in one package, the User-Agent token is the distinguishing signal. Add an ASYNC_USER_AGENT token 'PythonAsyncClient' and thread it through the async request paths (AsyncSSEFactory streaming headers, and the async feature requester, FDv2 polling, and event processor request headers) by parameterizing the shared _base_headers / _headers helpers. Sync behavior is unchanged. Register the new token in .sdk_metadata.json under the existing python-server-sdk entry, since async has no independent package. Implements SDK-2658. The analytics/event name 'python-server-sdk-async' already ships; billing confirmed it does not key off the User-Agent.
jsonbailey
marked this pull request as ready for review
September 3, 2026 14:31
jsonbailey
added a commit
that referenced
this pull request
Sep 3, 2026
keelerm84
approved these changes
Sep 4, 2026
jsonbailey
added a commit
that referenced
this pull request
Sep 25, 2026
🤖 I have created a release *beep* *boop* --- ## [9.18.0](9.17.0...9.18.0) (2026-09-25) ### Features * Add retry state for RETRY-spec backoff ([#522](#522)) ([e734558](e734558)) * Drive repeating tasks from a delay source ([9abe8cb](9abe8cb)) * Retry indefinitely after a data source failure instead of stopping permanently in FDv1 ([e17e173](e17e173)) * warn that payload filtering has no effect with FDv2 ([#518](#518)) ([296311f](296311f)) * Warn when the SDK is used in a forked process without postfork ([#512](#512)) ([75402e9](75402e9)) ### Bug Fixes * Add async modules to the readthedocs API reference ([#513](#513)) ([f40d3b2](f40d3b2)) * Log the cached-data evaluation warning only once per client ([#520](#520)) ([59ce998](59ce998)) * Read all items when a collection is empty ([#524](#524)) ([1087147](1087147)) * Repeating task wait duration is no longer reduced by a slow callback duration. ([9abe8cb](9abe8cb)) * Report a distinct User-Agent for the async client ([#516](#516)) ([514c467](514c467)) * Warn and use the documented default for an invalid poll interval or initial reconnect delay ([e17e173](e17e173)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > This PR **cuts release 9.18.0** by bumping the package version in `pyproject.toml`, `ldclient/version.py`, `.release-please-manifest.json`, and the provenance docs example, and by adding the **9.18.0** section to `CHANGELOG.md`. > > There is **no application code in the diff**—Release Please is packaging work that was already merged. The new changelog highlights **FDv1 data-source resilience** (indefinite retry after failures, RETRY-spec backoff state, repeating tasks driven by a delay source, and sane defaults/warnings for invalid poll/reconnect settings), **operational warnings** (forked process without `postfork`, FDv2 payload filtering), and **fixes** (empty-collection reads, repeating-task timing, one-time cached-data warnings, distinct async `User-Agent`, ReadTheDocs async API docs). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit eef08a1. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Jason Bailey <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
The async client (
AsyncLDClient) shipped reusing the synchronousPythonClient/<version>User-Agent, so LaunchDarkly cannot distinguish async traffic from sync. Because sync and async ship in the same package, the User-Agent token is the signal that tells them apart.This adds a distinct async token
PythonAsyncClientand threads it through every async request path.Changes
impl/http.py: addSYNC_USER_AGENT/ASYNC_USER_AGENTconstants;_base_headers(config, user_agent=SYNC_USER_AGENT).impl/util.py:_headers(config, user_agent=SYNC_USER_AGENT)passes the token through.ASYNC_USER_AGENT:impl/aio/transport.py—AsyncSSEFactorystreaming headersimpl/datasource/async_feature_requester.pyimpl/datasourcev2/async_polling.pyimpl/events/async_event_processor.py.sdk_metadata.json: register the token on the existingpython-server-sdkentry →userAgents: ["PythonClient", "PythonAsyncClient"].Sync behavior is unchanged (the default token is still
PythonClient).Design note
SDK-2658 originally proposed a separate
python-server-sdk-asyncsdk-meta registry entry. We chose to keep a single entry and add the async token to itsuserAgentsarray instead, because async has no independent package and is not a separately-tracked feature.The analytics/event SDK name
python-server-sdk-asyncalready ships (async_client.py); billing confirmed it does not key off the User-Agent, so this change is safe and additive.Tests
New
testing/impl/test_user_agent.pylocks the exact wire tokens for both sync and async via_base_headers/_headers.mypy/isort/pycodestyleclean; touched-component suites pass.Implements SDK-2658.
Note
Overview
Async
AsyncLDClienttraffic previously used the samePythonClient/<version>User-Agent as the sync client, so LaunchDarkly could not tell them apart in one package. This PR introducesPythonAsyncClientand wires it through shared header helpers while keeping sync defaults unchanged.SYNC_USER_AGENT/ASYNC_USER_AGENTare defined inimpl/http.py;_base_headersand_headerstake an optionaluser_agent(defaultPythonClient). Async paths passASYNC_USER_AGENT: SSE inimpl/aio/transport.py, FDv1 polling inasync_feature_requester.py, FDv2 polling inasync_polling.py, and event posts inasync_event_processor.py..sdk_metadata.jsonaddsPythonAsyncClientto the existingpython-server-sdkuserAgentslist.testing/impl/test_user_agent.pyasserts the exact wire User-Agent strings for sync and async.Reviewed by Cursor Bugbot for commit 32498ce. Bugbot is set up for automated code reviews on this repo. Configure here.