Skip to content

feat: saga state query API and reporting endpoints (#99)#114

Merged
mizrael merged 11 commits intodevelopfrom
feature/saga-state-query-api
Feb 13, 2026
Merged

feat: saga state query API and reporting endpoints (#99)#114
mizrael merged 11 commits intodevelopfrom
feature/saga-state-query-api

Conversation

@mizrael
Copy link
Owner

@mizrael mizrael commented Feb 13, 2026

Summary

Implements runtime saga state visibility as requested in #99. Adds a query interface, persistence implementations for all backends, HTTP reporting endpoints with OpenAPI support, and a sample application.

Changes

Core Query API (OpenSleigh)

  • ISagaStateQuery interface with GetByInstanceIdAsync, GetByCorrelationIdAsync, and GetAllAsync methods
  • DTOs: SagaInstanceInfo (with StateData for live saga state), ProcessedMessageInfo, SagaQueryFilter, PagedResult<T>

Persistence Implementations

  • InMemory: InMemorySagaStateRepository now implements ISagaStateQuery, extracting live state via reflection
  • SQL: SqlSagaStateQuery using EF Core with ISerializer for state deserialization
  • MongoDB: MongoSagaStateQuery using MongoDB driver with ISerializer for state deserialization
  • All backends register ISagaStateQuery in their DI extensions

Reporting Module (OpenSleigh.Reporting)

  • Minimal API endpoints: GET /sagas, GET /sagas/{id}, GET /sagas/correlation/{id}, GET /sagas/types
  • OpenAPI metadata (summaries, descriptions, response types, tags)
  • OpenAPI document generation (AddOpenApi/MapOpenApi) built-in for .NET 9+
  • Pagination validation (page >= 1, 1 <= pageSize <= 100)
  • Input validation on correlation endpoint (sagaType required)

Sample Application

  • PizzaTracker (samples/OpenSleigh.Samples.PizzaTracker): Pizza order tracking with 6-step saga flow, demonstrating real-time state queries via reporting endpoints

Infrastructure

  • Renamed TargetFrameworkVersion to SupportedTargetFrameworks in Versions.props to fix MSBuild property collision with SDK built-in
  • Added .claude/settings.local.json to .gitignore

Safety and Thread Safety

  • ConcurrentDictionary snapshot (.ToList()) before enumeration in all InMemory query methods
  • Deserialization wrapped in try-catch for corrupted state data (SQL/Mongo)
  • Lock state checks both LockId and LockTime consistently

Tests

  • 13 unit tests for InMemory query implementation
  • 13 unit tests for reporting endpoints (including pagination validation)
  • All 274 tests passing

Closes #99

- Add ISagaStateQuery interface with DTOs (SagaInstanceInfo, PagedResult, etc.)
- Implement query for all backends: InMemory, SQL, MongoDB
- Include StateData in query results for runtime saga inspection
- Add OpenSleigh.Reporting project with Minimal API endpoints
- Register ISagaStateQuery in all backend DI extensions
- Add pagination validation, deserialization safety, snapshot for thread safety
- Add unit tests for InMemory query and reporting endpoints
A pizza order tracking sample using InMemory persistence and transport.
Orders progress through 6 saga steps (Received → Preparing → Baking →
Quality Check → Out for Delivery → Delivered) with ~2s delays to allow
querying intermediate state via the OpenSleigh.Reporting endpoints.

Demonstrates: MapOpenSleighReporting(), ISagaStateQuery, live StateData,
filtering by completion status, and pagination.
Add summaries, descriptions, response types, and error codes to all
saga reporting endpoints. Grouped under 'OpenSleigh' tag for Swagger UI.
Add Microsoft.AspNetCore.OpenApi with TFM-conditional versioning
(8.0.24 for net8.0, 9.0.13 for net9.0, 10.0.3 for net10.0).
OpenAPI spec served at /openapi/v1.json with full schema and metadata.
Use #if !NET8_0 guards for AddOpenApi/MapOpenApi calls and remove
the net8.0 package reference since the API is only available in 9.0+.
The custom MSBuild property name collided with the SDK's built-in
TargetFrameworkVersion property, causing VS build failures when
Microsoft.AspNetCore.OpenApi package was referenced.

Also moves OpenAPI into OpenSleigh.Reporting (AddOpenApi/MapOpenApi
called automatically by AddOpenSleighReporting/MapOpenSleighReporting,
guarded with #if NET9_0_OR_GREATER for net8.0 compat) and simplifies
PizzaTracker to target net10.0 only.
- Snapshot ConcurrentDictionary in GetByCorrelationIdAsync (race condition)
- Validate sagaType parameter in correlation endpoint (400 if missing)
- Add XML doc security warning on MapOpenSleighReporting
@codecov-commenter
Copy link

codecov-commenter commented Feb 13, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 87.32394% with 36 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.34%. Comparing base (d63ade4) to head (434b269).
⚠️ Report is 12 commits behind head on develop.

Files with missing lines Patch % Lines
...Sleigh.Reporting/EndpointRouteBuilderExtensions.cs 0.00% 29 Missing ⚠️
...penSleigh.Reporting/ServiceCollectionExtensions.cs 0.00% 4 Missing ⚠️
...OpenSleigh.InMemory/InMemorySagaStateRepository.cs 94.11% 1 Missing and 2 partials ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop     #114      +/-   ##
===========================================
+ Coverage    81.63%   82.34%   +0.70%     
===========================================
  Files           77       86       +9     
  Lines         2287     2571     +284     
  Branches       268      301      +33     
===========================================
+ Hits          1867     2117     +250     
- Misses         317      350      +33     
- Partials       103      104       +1     
Files with missing lines Coverage Δ
...penSleigh.Persistence.Mongo/MongoSagaStateQuery.cs 100.00% <100.00%> (ø)
...rc/OpenSleigh.Persistence.SQL/SqlSagaStateQuery.cs 100.00% <100.00%> (ø)
...rc/OpenSleigh.Reporting/Endpoints/SagaEndpoints.cs 100.00% <100.00%> (ø)
src/OpenSleigh/Queries/PagedResult.cs 100.00% <100.00%> (ø)
src/OpenSleigh/Queries/ProcessedMessageInfo.cs 100.00% <100.00%> (ø)
src/OpenSleigh/Queries/SagaInstanceInfo.cs 100.00% <100.00%> (ø)
src/OpenSleigh/Queries/SagaQueryFilter.cs 100.00% <100.00%> (ø)
...OpenSleigh.InMemory/InMemorySagaStateRepository.cs 96.66% <94.11%> (-0.77%) ⬇️
...penSleigh.Reporting/ServiceCollectionExtensions.cs 0.00% <0.00%> (ø)
...Sleigh.Reporting/EndpointRouteBuilderExtensions.cs 0.00% <0.00%> (ø)

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d63ade4...434b269. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a 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 implements a comprehensive saga state query and reporting API for OpenSleigh, addressing issue #99. It enables runtime visibility into saga instances across all persistence backends (InMemory, SQL, MongoDB) through a unified query interface, and exposes this functionality via HTTP endpoints with OpenAPI support.

Changes:

  • Added ISagaStateQuery interface with methods to query saga instances by ID, correlation ID, or retrieve all with filtering/pagination
  • Implemented query support in all persistence backends using appropriate techniques (reflection for InMemory, EF Core for SQL, MongoDB driver for Mongo)
  • Created OpenSleigh.Reporting module with ASP.NET Core Minimal API endpoints and OpenAPI metadata
  • Included PizzaTracker sample application demonstrating the query API and reporting endpoints
  • Renamed MSBuild property from TargetFrameworkVersion to SupportedTargetFrameworks to avoid SDK collision

Reviewed changes

Copilot reviewed 58 out of 59 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/OpenSleigh/Queries/ISagaStateQuery.cs Core query interface with GetByInstanceIdAsync, GetByCorrelationIdAsync, and GetAllAsync methods
src/OpenSleigh/Queries/SagaInstanceInfo.cs DTO containing saga instance metadata including live StateData
src/OpenSleigh/Queries/SagaQueryFilter.cs Filter DTO for querying sagas by type and completion status with pagination
src/OpenSleigh/Queries/PagedResult.cs Generic paged result DTO
src/OpenSleigh/Queries/ProcessedMessageInfo.cs DTO for processed message metadata
src/OpenSleigh.InMemory/InMemorySagaStateRepository.cs InMemory implementation of ISagaStateQuery using reflection to extract state data
src/OpenSleigh.InMemory/InMemoryBusConfiguratorExtensions.cs DI registration mapping both ISagaStateRepository and ISagaStateQuery to singleton instance
src/OpenSleigh.Persistence.SQL/SqlSagaStateQuery.cs SQL implementation using EF Core with ISerializer for state deserialization
src/OpenSleigh.Persistence.SQLServer/SqlBusConfiguratorExtensions.cs DI registration for SQL Server query implementation
src/OpenSleigh.Persistence.PostgreSQL/SqlBusConfiguratorExtensions.cs DI registration for PostgreSQL query implementation
src/OpenSleigh.Persistence.Mongo/MongoSagaStateQuery.cs MongoDB implementation using driver with ISerializer for state deserialization
src/OpenSleigh.Persistence.Mongo/MongoBusConfiguratorExtensions.cs DI registration for MongoDB query implementation
src/OpenSleigh.Reporting/Endpoints/SagaEndpoints.cs Minimal API endpoint handlers with validation for pagination and required parameters
src/OpenSleigh.Reporting/EndpointRouteBuilderExtensions.cs Extension method to map reporting endpoints with OpenAPI metadata and security documentation
src/OpenSleigh.Reporting/ServiceCollectionExtensions.cs DI extension to register OpenAPI for .NET 9+
src/OpenSleigh.Reporting/OpenSleigh.Reporting.csproj New reporting module project with framework-specific OpenAPI package references
tests/OpenSleigh.Tests/Queries/InMemorySagaStateQueryTests.cs Comprehensive unit tests (13 tests) for InMemory query implementation
tests/OpenSleigh.Reporting.Tests/SagaEndpointsTests.cs Unit tests (13 tests) for reporting endpoints including validation scenarios
samples/OpenSleigh.Samples.PizzaTracker/* Complete sample application demonstrating query API and reporting endpoints
Versions.props Renamed TargetFrameworkVersion to SupportedTargetFrameworks
.gitignore Added .claude/settings.local.json
src/OpenSleigh.sln Added new projects and build configurations
All .csproj files Updated to use $(SupportedTargetFrameworks)

- 16 unit tests for SqlSagaStateQuery using EF Core InMemory provider
  (queries, filtering, pagination, state deserialization, lock detection)
- 3 tests for GetByCorrelationId sagaType validation (null/empty/whitespace)
- Total: 293 tests passing
@mizrael mizrael merged commit cf4b0c3 into develop Feb 13, 2026
3 checks passed
@mizrael mizrael deleted the feature/saga-state-query-api branch February 13, 2026 15:12
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.

How can I get the state data of a running saga?

3 participants