Repository navigation
.NET: Add Redis checkpoint store for workflows - #9253
Draft
Murat Ay (Murat7Ay) wants to merge 2 commits into
Draft
Murat Ay (Murat7Ay) wants to merge 2 commits into
Murat Ay (Murat7Ay) wants to merge 2 commits into
Conversation
Add Microsoft.Agents.AI.Redis (alpha, not packable yet) with RedisCheckpointStore, a JsonCheckpointStore on StackExchange.Redis. Per session it keeps a sorted set of checkpoint ids scored by a commit counter, a hash with the checkpoint JSON and a hash with parent ids, written atomically by a Lua script. The index is returned in commit order (as ICheckpointStore requires), all keys of a session share a Redis Cluster hash tag, and an optional time to live expires a session as a whole. Unit tests run against a mocked IDatabase; server tests run against a real Redis and are skipped when none is reachable. Adds the CheckpointWithRedis workflow sample. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Murat Ay (Murat7Ay)
had a problem deploying
to
github-app-auth
October 10, 2026 19:13 — with
GitHub Actions
Error
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Redis hash-tag edge cases break cluster operation, and the sample’s checkpoint stopping point is timing-dependent.
2 open findings
What changed in this PR
Adds a Redis-backed durable checkpoint store for distributed .NET workflows.
Changes:
- Implements atomic, ordered Redis checkpoint persistence with optional TTL.
- Adds mocked and live-server tests.
- Adds a checkpoint-resumption sample and project registrations.
| File | Description |
|---|---|
dotnet/src/Microsoft.Agents.AI.Redis/RedisCheckpointStore.cs |
Implements Redis checkpoint storage. |
dotnet/src/Microsoft.Agents.AI.Redis/RedisCheckpointStoreOptions.cs |
Defines Redis configuration options. |
dotnet/src/Microsoft.Agents.AI.Redis/Microsoft.Agents.AI.Redis.csproj |
Defines the new integration project. |
dotnet/tests/Microsoft.Agents.AI.Redis.UnitTests/RedisFixture.cs |
Provides live Redis test setup. |
dotnet/tests/Microsoft.Agents.AI.Redis.UnitTests/RedisCheckpointStoreTests.cs |
Tests store behavior with mocks. |
dotnet/tests/Microsoft.Agents.AI.Redis.UnitTests/RedisCheckpointStoreServerTests.cs |
Tests against a Redis server. |
dotnet/tests/Microsoft.Agents.AI.Redis.UnitTests/GuessNumberWorkflow.cs |
Supplies a resumable test workflow. |
dotnet/tests/Microsoft.Agents.AI.Redis.UnitTests/Microsoft.Agents.AI.Redis.UnitTests.csproj |
Defines the test project. |
dotnet/samples/03-workflows/Checkpoint/CheckpointWithRedis/Program.cs |
Demonstrates checkpoint resumption. |
dotnet/samples/03-workflows/Checkpoint/CheckpointWithRedis/WorkflowFactory.cs |
Defines the sample workflow. |
dotnet/samples/03-workflows/Checkpoint/CheckpointWithRedis/README.md |
Documents sample usage. |
dotnet/samples/03-workflows/Checkpoint/CheckpointWithRedis/CheckpointWithRedis.csproj |
Defines the sample project. |
dotnet/samples/03-workflows/README.md |
Lists the Redis sample. |
dotnet/eng/verify-samples/WorkflowSamples.cs |
Registers sample verification. |
dotnet/Directory.Packages.props |
Pins StackExchange.Redis. |
dotnet/agent-framework-src-and-tests.slnf |
Registers source and test projects. |
dotnet/agent-framework-dotnet.slnx |
Registers all new projects. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Author
|
@microsoft-github-policy-service agree |
…erministic
Escape '%', '{' and '}' in the session id inside the hash tag and reject
braces in KeyPrefix, so all keys of a session always share one valid
Redis Cluster hash tag. A session id such as "}abc" produced an empty
tag before, which spread the keys over different slots and made the
create script fail with CROSSSLOT.
Add unit tests that compute the cluster slot (CRC16) of the keys for
awkward session ids and prefixes, and server tests with such session
ids (run against standalone Redis and a single-node Redis Cluster).
Run the first part of the CheckpointWithRedis sample in lockstep mode,
so it stops exactly after the fourth checkpoint and resumes from it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
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.


Motivation & Context
Workflows that run across processes, pods or machines need a durable, shared checkpoint store. On .NET the built-in stores are in-memory and file system (process-exclusive), plus Cosmos DB. Redis is a common choice for this kind of short-lived, shared state (Azure Managed Redis, ElastiCache, self-hosted, Kubernetes), and #2401 asks for a Redis-backed checkpoint store. The earlier .NET attempt, #2799, was closed as outdated with its Copilot review comments still open; this PR is a fresh implementation on current
mainand addresses all of them (details below).Description & Review Guide
What are the major changes?
Microsoft.Agents.AI.Redis(VersionSuffix=alpha,IsPackable=falseuntil maintainers want to publish it, as was done for Valkey) withRedisCheckpointStore : JsonCheckpointStoreandRedisCheckpointStoreOptions(KeyPrefix,Database,TimeToLive). It is built on StackExchange.Redis, which Add Redis-backed checkpoint storage for distributed workflow persistence #2401 names. Types live inMicrosoft.Agents.AI.Workflows.Checkpointing, likeCosmosCheckpointStore.INCR), a hash with the checkpoint JSON (stored verbatim, so$typediscriminators stay first) and a hash with parent ids. One Lua script writes all of it atomically.RetrieveIndexAsyncreturns checkpoints in commit order, asICheckpointStorerequires andCheckpointManager.GetLatestCheckpointAsyncrelies on. It stays correct for many checkpoints in the same second and for several processes writing to the same session.{,}and%are escaped, andKeyPrefixmay not contain braces), so the store works on Redis Cluster. The optionalTimeToLiveis reset on every new checkpoint and covers all keys of the session, so a session expires as a whole.IConnectionMultiplexerthe application owns. It holds no other resources, so it is notIDisposableand is safe to share between threads.KeyNotFoundException, likeFileSystemJsonCheckpointStore.Microsoft.Agents.AI.Redis.UnitTests: 40 unit tests against a mockedIDatabase(always run), and 12 tests against a real Redis server that follow the Cosmos emulator pattern:REDIS_CONNECTION_STRING(defaultlocalhost:6379), skipped when no server is reachable, failing instead whenREDIS_AVAILABLE=true. The server tests include a real workflow that is resumed from Redis with a new connection, store and workflow instance.samples/03-workflows/Checkpoint/CheckpointWithRedis: run, stop part way, then resume from the latest checkpoint found in Redis. Added to the solution, the 03-workflows README andeng/verify-samples(skipped there because it needs a Redis server).What is the impact of these changes? Additive only: a new package, test project and sample. No existing public API changes. New central package version:
StackExchange.Redis3.4.0.What do you want reviewers to focus on?
Microsoft.Agents.AI.Redispackage instead of extendingMicrosoft.Agents.AI.Valkey, because: Add Redis-backed checkpoint storage for distributed workflow persistence #2401 asks for StackExchange.Redis; Python already shipsagent-framework-redis, so the name matches across languages; and in the Valkey PR (.NET: Adds Valkey to chat message history - issue 5445 #5542) a reviewer asked whether that package should be called Redis, and the Valkey maintainers preferred to keep the Valkey package Valkey-specific (Valkey.Glide only guarantees Redis 6.2–7.2). The Valkey package also has no dependency on Workflows today. I'm happy to move the store into the Valkey package if you prefer.FeatureIndexbit, sincedocs/specs/feature-usage-bit-registry.mdtreats new bits as a maintainer decision. I can add aredisrow (next free .NET index is 75) if you want one.IConnectionMultiplexer.How the Copilot review comments on #2799 are addressed
_disposedchecked without synchronization (3 comments)RedisCheckpointStore.cs_disposedflag and is notIDisposable. All fields are readonly and set in the constructor, so there is no race to guard.varinstead of explicit types (11 comments)Program.csTargetFramework(singular) for a single target.csproj<TargetFrameworks>:samples/Directory.Build.propssetsTargetFrameworks(net10.0;net472), and a singularTargetFrameworkwould not override it. All samples in the repo use the plural form.sealed.this._disposedin teststhis.throughout.disposingparameterDispose(bool)anymore.Other differences from #2799:
ToUnixTimeSeconds(), so checkpoints created in the same second came back in GUID order and the wrong one could be treated as the latest. A per-session counter fixes this;RetrieveIndexAsync_ReturnsCommitOrderPerSessionAndFiltersByParentAsyncwrites 25 checkpoints in a row and fails if the score is changed to a constant.MULTI, but those keys hash to different slots, which Redis Cluster rejects (CROSSSLOT). Hash-tagged keys fix this.GETper checkpoint; this uses oneHMGET.03-workflows/Checkpointlayout.Local test run
Windows, .NET SDK 10.0.401, Redis 7 (
redis:7-alpinein Docker), standalone and a single-node Redis Cluster:dotnet build tests/Microsoft.Agents.AI.Redis.UnitTests: 0 warnings, 0 errors.dotnet test --project tests/Microsoft.Agents.AI.Redis.UnitTests -f <tfm>withREDIS_CONNECTION_STRINGandREDIS_AVAILABLE=true: net10.0, net9.0 and net8.0 eachtotal: 52, failed: 0, succeeded: 52, skipped: 0, against both standalone Redis and Redis Cluster.total: 52, succeeded: 40, skipped: 12("Redis is not available").dotnet format <csproj> --verify-no-changeson the new package, test project, sample andeng/verify-samples: no changes.Workflow completed with result: 42 found in 7 tries!.Related Issue
Fixes #2401
Supersedes #2799 (closed as outdated). There is no other open PR for this issue. #2401 also covers Python; this PR is .NET only.
AI Assistance
AI assistance details: implementation, tests, sample and PR description were drafted with an AI coding assistant (Claude), starting from a Redis checkpoint store I already maintain in my own project. I reviewed the design and code and ran the builds and tests listed above against a real Redis server.
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.