dotnet-cqrs/Svrnty.CQRS.Events.Abstractions/Sagas/ISaga.cs

169 lines
4.0 KiB
C#

using System;
using System.Threading;
using System.Threading.Tasks;
namespace Svrnty.CQRS.Events.Abstractions.Sagas;
/// <summary>
/// Represents a long-running business process (saga) that coordinates multiple steps.
/// </summary>
/// <remarks>
/// <para>
/// Sagas implement distributed transactions using compensation rather than two-phase commit.
/// Each step has a corresponding compensation action that undoes its effects.
/// </para>
/// <para>
/// <strong>Saga Pattern:</strong>
/// - Execute steps sequentially
/// - If a step fails, execute compensations in reverse order
/// - Supports timeouts, retries, and state persistence
/// </para>
/// </remarks>
public interface ISaga
{
/// <summary>
/// Unique identifier for this saga instance.
/// </summary>
string SagaId { get; }
/// <summary>
/// Correlation ID linking this saga to related events/commands.
/// </summary>
string CorrelationId { get; }
/// <summary>
/// Name of the saga type (for tracking and monitoring).
/// </summary>
string SagaName { get; }
}
/// <summary>
/// Represents a single step in a saga.
/// </summary>
public interface ISagaStep
{
/// <summary>
/// Name of this step.
/// </summary>
string StepName { get; }
/// <summary>
/// Execute the step's action.
/// </summary>
/// <param name="context">The saga execution context.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Task representing the async operation.</returns>
Task ExecuteAsync(ISagaContext context, CancellationToken cancellationToken = default);
/// <summary>
/// Compensate (undo) the step's action.
/// </summary>
/// <param name="context">The saga execution context.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Task representing the async operation.</returns>
Task CompensateAsync(ISagaContext context, CancellationToken cancellationToken = default);
}
/// <summary>
/// Context available to saga steps during execution.
/// </summary>
public interface ISagaContext
{
/// <summary>
/// The saga instance.
/// </summary>
ISaga Saga { get; }
/// <summary>
/// Current state of the saga.
/// </summary>
SagaState State { get; }
/// <summary>
/// Saga data (shared state across steps).
/// </summary>
ISagaData Data { get; }
/// <summary>
/// Get a value from saga data.
/// </summary>
T? Get<T>(string key);
/// <summary>
/// Set a value in saga data.
/// </summary>
void Set<T>(string key, T value);
/// <summary>
/// Check if a key exists in saga data.
/// </summary>
bool Contains(string key);
}
/// <summary>
/// Saga data storage (key-value pairs).
/// </summary>
public interface ISagaData
{
/// <summary>
/// Get a value.
/// </summary>
T? Get<T>(string key);
/// <summary>
/// Set a value.
/// </summary>
void Set<T>(string key, T value);
/// <summary>
/// Check if a key exists.
/// </summary>
bool Contains(string key);
/// <summary>
/// Get all data as dictionary.
/// </summary>
System.Collections.Generic.IDictionary<string, object> GetAll();
}
/// <summary>
/// State of a saga instance.
/// </summary>
public enum SagaState
{
/// <summary>
/// Saga has not started yet.
/// </summary>
NotStarted = 0,
/// <summary>
/// Saga is currently executing steps.
/// </summary>
Running = 1,
/// <summary>
/// Saga completed successfully.
/// </summary>
Completed = 2,
/// <summary>
/// Saga is compensating (rolling back).
/// </summary>
Compensating = 3,
/// <summary>
/// Saga was compensated (rolled back).
/// </summary>
Compensated = 4,
/// <summary>
/// Saga failed and could not be compensated.
/// </summary>
Failed = 5,
/// <summary>
/// Saga is paused waiting for external event.
/// </summary>
Paused = 6
}