-
Notifications
You must be signed in to change notification settings - Fork 892
.NET: Add Redis checkpoint store implementation for workflows #2799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Implement RedisCheckpointStore for distributed, durable checkpoint storage: - Support connection string, ConfigurationOptions, and IConnectionMultiplexer - TTL-based automatic checkpoint expiration - Parent-child checkpoint relationships for workflow history tracking - Extension methods for easy integration Includes unit tests and sample application.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds a Redis-based checkpoint store implementation for the Agent Framework's workflow system, enabling distributed and durable checkpoint storage in production environments. The implementation follows the existing patterns from Microsoft.Agents.AI.CosmosNoSql.
Key changes:
- New
RedisCheckpointStorewith support for TTL-based expiration and parent-child checkpoint relationships - Comprehensive unit test suite with 27 tests using skippable facts for Redis availability
- Sample application demonstrating Redis checkpoint usage with workflow state management
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| dotnet/src/Microsoft.Agents.AI.Redis/RedisCheckpointStore.cs | Core Redis checkpoint store implementation with generic and non-generic variants |
| dotnet/src/Microsoft.Agents.AI.Redis/RedisCheckpointStoreOptions.cs | Configuration options for key prefix, TTL, and database selection |
| dotnet/src/Microsoft.Agents.AI.Redis/RedisWorkflowExtensions.cs | Extension methods for creating checkpoint stores with various configurations |
| dotnet/src/Microsoft.Agents.AI.Redis/Microsoft.Agents.AI.Redis.csproj | Project file with StackExchange.Redis dependency |
| dotnet/tests/Microsoft.Agents.AI.Redis.UnitTests/RedisCheckpointStoreTests.cs | Comprehensive test suite covering all checkpoint operations |
| dotnet/tests/Microsoft.Agents.AI.Redis.UnitTests/RedisCollectionFixture.cs | Test collection fixture to prevent parallel test execution |
| dotnet/tests/Microsoft.Agents.AI.Redis.UnitTests/Microsoft.Agents.AI.Redis.UnitTests.csproj | Test project configuration |
| dotnet/samples/GettingStarted/Workflows/Checkpoint/CheckpointWithRedis/Program.cs | Sample demonstrating Redis checkpoint usage with parent-child relationships |
| dotnet/samples/GettingStarted/Workflows/Checkpoint/CheckpointWithRedis/CheckpointWithRedis.csproj | Sample project configuration |
| dotnet/agent-framework-dotnet.slnx | Solution file updates to include new projects |
| dotnet/Directory.Packages.props | Added StackExchange.Redis package version |
| if (this._disposed) | ||
| { | ||
| throw new ObjectDisposedException(this.GetType().FullName); | ||
| } | ||
| #pragma warning restore CA1513 |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The '_disposed' field is checked without thread synchronization. In multi-threaded scenarios, this could lead to race conditions where Dispose is called while an operation is in progress. Consider using a lock or volatile keyword, or better yet, use ObjectDisposedException.ThrowIf with proper synchronization.
dotnet/samples/GettingStarted/Workflows/Checkpoint/CheckpointWithRedis/Program.cs
Show resolved
Hide resolved
dotnet/samples/GettingStarted/Workflows/Checkpoint/CheckpointWithRedis/Program.cs
Show resolved
Hide resolved
| if (this._disposed) | ||
| { | ||
| throw new ObjectDisposedException(this.GetType().FullName); | ||
| } | ||
| #pragma warning restore CA1513 |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The '_disposed' field is checked without thread synchronization. In multi-threaded scenarios, this could lead to race conditions where Dispose is called while an operation is in progress. Consider using a lock or volatile keyword, or better yet, use ObjectDisposedException.ThrowIf with proper synchronization.
| if (this._disposed) | ||
| { | ||
| throw new ObjectDisposedException(this.GetType().FullName); | ||
| } | ||
| #pragma warning restore CA1513 |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The '_disposed' field is checked without thread synchronization. In multi-threaded scenarios, this could lead to race conditions where Dispose is called while an operation is in progress. Consider using a lock or volatile keyword, or better yet, use ObjectDisposedException.ThrowIf with proper synchronization.
dotnet/samples/GettingStarted/Workflows/Checkpoint/CheckpointWithRedis/Program.cs
Show resolved
Hide resolved
dotnet/samples/GettingStarted/Workflows/Checkpoint/CheckpointWithRedis/Program.cs
Show resolved
Hide resolved
dotnet/samples/GettingStarted/Workflows/Checkpoint/CheckpointWithRedis/Program.cs
Show resolved
Hide resolved
...t/samples/GettingStarted/Workflows/Checkpoint/CheckpointWithRedis/CheckpointWithRedis.csproj
Outdated
Show resolved
Hide resolved
|
|
||
| protected virtual void Dispose(bool disposing) | ||
| { | ||
| // Connection multiplexer disposed in DisposeAsync |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 'disposing' parameter is not used in the Dispose method. While this is a valid pattern for implementing IDisposable, the parameter should either be used or the method body should indicate why it's not needed with a comment.
| // Connection multiplexer disposed in DisposeAsync | |
| // The 'disposing' parameter is unused because connection multiplexer is disposed in DisposeAsync. |
…ithRedis/CheckpointWithRedis.csproj Co-authored-by: Copilot <[email protected]>
Motivation and Context
Related to #2401 (C# implementation) The Agent Framework currently supports only in-memory and flat file checkpoint storage, which limits adoption in production environments. Workflows often need to be resumed across processes, pods, or machines, requiring a distributed and durable checkpoint store.
Description
Implement
RedisCheckpointStorefor distributed, durable checkpoint storage in .NET:Features:
ConfigurationOptions, andIConnectionMultiplexerfor flexible Redis connectivityRedisCheckpointStoreOptions.TimeToLiveCreateRedisCheckpointStore,CreateRedisCheckpointStoreWithTtl) for easy integrationFiles added:
src/Microsoft.Agents.AI.Redis/- Core implementationtests/Microsoft.Agents.AI.Redis.UnitTests/- Unit tests (27 tests)samples/GettingStarted/Workflows/Checkpoint/CheckpointWithRedis/- Sample applicationDependencies:
Uses
StackExchange.Redisfor connection pooling and resilienceFollows the same patterns as
Microsoft.Agents.AI.CosmosNoSqlContribution Checklist