Skip to content

feat: Add async migration support - #470

Merged
jsonbailey merged 9 commits into
mainfrom
jb/sdk-2767/async-migrations
Aug 4, 2026
Merged

feat: Add async migration support#470
jsonbailey merged 9 commits into
mainfrom
jb/sdk-2767/async-migrations

Conversation

@jsonbailey

@jsonbailey jsonbailey commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Adds the async migration surface for the async Python SDK — AsyncMigrator, AsyncMigratorBuilder, AsyncMigrationConfig, and the AsyncMigratorFn type — in ldclient/migrations/async_migrator.py, eagerly exported from ldclient/migrations/__init__.py (import-cheap: asyncio stdlib only, no aiohttp).

Also carries the migration config/builder dedup shared by the sync and async surfaces: types.py gains _MigrationConfigBase[_MigratorFnT] (Generic) and _MigratorBuilderBase (fluent-setter mixin), and migrator.py's MigratorBuilder is re-based onto that mixin. These are behavior-preserving refactors of already-released sync code.

The public async classes carry experimental .. caution:: blocks.

Self-contained: depends only on already-merged foundation work. The AsyncLDClient/Context references are TYPE_CHECKING-only (annotations kept lazy via from __future__ import annotations); no runtime import of any not-yet-merged async module.

No CHANGELOG or version changes (handled at release).

Tracked internally: SDK-2767


Note

Medium Risk
New experimental migration execution path affects dual-origin reads/writes and telemetry during flag-driven cutovers; behavior is well-tested but not production-stable per API warnings.

Overview
Adds an experimental async migration API for the async Python SDK, mirroring the sync migrator’s stage-driven read/write behavior with coroutine-based old/new handlers.

New surface in async_migrator.py: AsyncMigrator / AsyncMigratorImpl, AsyncMigratorBuilder, AsyncMigrationConfig, AsyncMigratorFn, and AsyncExecutor. Reads honor ExecutionOrder (parallel, serial, random) via asyncio.gather and optional consistency checks; writes run authoritative-first and skip the second origin on authoritative failure. migration_variation is awaited; track_migration_op stays synchronous. Write cancellation logs a warning, still emits migration telemetry in finally, and propagates CancelledError without undoing a completed authoritative write.

ldclient/migrations/__init__.py re-exports the new types. test_async_migrator.py adds broad pytest coverage (builder validation, payloads, tracking, consistency, execution order, cancellation) using a FakeAsyncClient.

Reviewed by Cursor Bugbot for commit d35a24c. Bugbot is set up for automated code reviews on this repo. Configure here.

@jsonbailey
jsonbailey force-pushed the jb/sdk-2767/async-migrations branch from abe7dac to c735e0e Compare July 27, 2026 22:01
@jsonbailey

Copy link
Copy Markdown
Contributor Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit c735e0e. Configure here.

@jsonbailey
jsonbailey force-pushed the jb/sdk-2767/async-migrations branch from c735e0e to ec7746a Compare July 29, 2026 19:31
…ic base

Drop _MigrationConfigBase and give MigrationConfig and AsyncMigrationConfig
their own bodies. The shared base saved only a few trivial passthrough
properties while adding generic indirection, and full duplication matches how
Config/AsyncConfig are handled. MigrationConfig reverts to its pre-async
standalone form.
Give MigratorBuilder and AsyncMigratorBuilder their own read_execution_order/
track_latency/track_errors methods instead of sharing a base for three trivial
property setters. MigratorBuilder and types.py revert to their pre-async form.
@jsonbailey
jsonbailey marked this pull request as ready for review July 30, 2026 21:59
@jsonbailey
jsonbailey requested a review from a team as a code owner July 30, 2026 21:59
Comment thread ldclient/migrations/__init__.py Outdated
Comment thread ldclient/migrations/types.py Outdated
Comment thread ldclient/migrations/async_migrator.py
Comment thread ldclient/migrations/async_migrator.py
Move track_migration_op into a finally so a write cancelled mid-operation still emits its migration op event. The CancelledError propagates and no WriteResult is returned, but the event now records which origins were written, so a partial write is reported rather than lost.

Reads are left as-is: a cancelled read has no side effect and loses its consistency measurement, so a partial read event carries no useful signal.
Comment thread ldclient/migrations/async_migrator.py
On an early cancel (before any origin write completes) OpTracker.build returned "no origins were invoked" and the client logged a spurious error. Guard the write finally with OpTracker.has_invocations so the event is only emitted when at least one origin ran. Drop the now-redundant finally comment.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 using default effort 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.

Reviewed by Cursor Bugbot for commit ef02557. Configure here.

Comment thread ldclient/migrations/async_migrator.py
Replace the has_invocations guard with a warning logged when a migration write is cancelled before completion, and call track_migration_op unconditionally. A cancelled dual write is a torn write worth surfacing, and the warning is co-located with the client's build error on an early cancel. Revert the now-unused OpTracker.has_invocations accessor.
@jsonbailey
jsonbailey merged commit 577d51e into main Aug 4, 2026
15 checks passed
@jsonbailey
jsonbailey deleted the jb/sdk-2767/async-migrations branch August 4, 2026 16:30
@jsonbailey jsonbailey changed the title feat: Add async migrations feat: Add async migration support Aug 4, 2026
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