125 lines
4.4 KiB
C#
125 lines
4.4 KiB
C#
using System;
|
|
using Svrnty.CQRS.Events.Abstractions.Storage;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Svrnty.CQRS.Events.Abstractions.Storage;
|
|
|
|
/// <summary>
|
|
/// Store for tracking read receipts (consumer acknowledgments of processed events).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <strong>Purpose:</strong>
|
|
/// Read receipts provide visibility into consumer progress through event streams.
|
|
/// Unlike idempotency (which prevents duplicates), read receipts track progress.
|
|
/// </para>
|
|
/// <para>
|
|
/// <strong>Use Cases:</strong>
|
|
/// - Dashboard showing consumer lag/progress
|
|
/// - Resuming from last processed position
|
|
/// - Monitoring consumer health
|
|
/// - Detecting stuck consumers
|
|
/// </para>
|
|
/// </remarks>
|
|
public interface IReadReceiptStore
|
|
{
|
|
/// <summary>
|
|
/// Records that a consumer has successfully processed an event.
|
|
/// </summary>
|
|
/// <param name="consumerId">The consumer identifier.</param>
|
|
/// <param name="streamName">The name of the event stream.</param>
|
|
/// <param name="eventId">The unique event identifier.</param>
|
|
/// <param name="offset">The event's offset/position in the stream.</param>
|
|
/// <param name="acknowledgedAt">When the event was acknowledged.</param>
|
|
/// <param name="cancellationToken">Cancellation token.</param>
|
|
Task AcknowledgeEventAsync(
|
|
string consumerId,
|
|
string streamName,
|
|
string eventId,
|
|
long offset,
|
|
DateTimeOffset acknowledgedAt,
|
|
CancellationToken cancellationToken = default);
|
|
|
|
/// <summary>
|
|
/// Gets the last acknowledged offset for a consumer on a specific stream.
|
|
/// </summary>
|
|
/// <param name="consumerId">The consumer identifier.</param>
|
|
/// <param name="streamName">The name of the event stream.</param>
|
|
/// <param name="cancellationToken">Cancellation token.</param>
|
|
/// <returns>The last acknowledged offset, or null if no receipts exist.</returns>
|
|
Task<long?> GetLastAcknowledgedOffsetAsync(
|
|
string consumerId,
|
|
string streamName,
|
|
CancellationToken cancellationToken = default);
|
|
|
|
/// <summary>
|
|
/// Gets statistics about a consumer's progress on a stream.
|
|
/// </summary>
|
|
/// <param name="consumerId">The consumer identifier.</param>
|
|
/// <param name="streamName">The name of the event stream.</param>
|
|
/// <param name="cancellationToken">Cancellation token.</param>
|
|
/// <returns>Consumer progress statistics.</returns>
|
|
Task<ConsumerProgress?> GetConsumerProgressAsync(
|
|
string consumerId,
|
|
string streamName,
|
|
CancellationToken cancellationToken = default);
|
|
|
|
/// <summary>
|
|
/// Gets all consumers that are tracking a specific stream.
|
|
/// </summary>
|
|
/// <param name="streamName">The name of the event stream.</param>
|
|
/// <param name="cancellationToken">Cancellation token.</param>
|
|
/// <returns>List of consumer IDs tracking this stream.</returns>
|
|
Task<IReadOnlyList<string>> GetConsumersForStreamAsync(
|
|
string streamName,
|
|
CancellationToken cancellationToken = default);
|
|
|
|
/// <summary>
|
|
/// Cleans up old read receipts.
|
|
/// </summary>
|
|
/// <param name="olderThan">Delete receipts older than this timestamp.</param>
|
|
/// <param name="cancellationToken">Cancellation token.</param>
|
|
/// <returns>Number of receipts deleted.</returns>
|
|
Task<int> CleanupAsync(
|
|
DateTimeOffset olderThan,
|
|
CancellationToken cancellationToken = default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents a consumer's progress on a specific stream.
|
|
/// </summary>
|
|
public sealed class ConsumerProgress
|
|
{
|
|
/// <summary>
|
|
/// The consumer identifier.
|
|
/// </summary>
|
|
public required string ConsumerId { get; init; }
|
|
|
|
/// <summary>
|
|
/// The stream name.
|
|
/// </summary>
|
|
public required string StreamName { get; init; }
|
|
|
|
/// <summary>
|
|
/// The last acknowledged offset.
|
|
/// </summary>
|
|
public required long LastOffset { get; init; }
|
|
|
|
/// <summary>
|
|
/// When the last event was acknowledged.
|
|
/// </summary>
|
|
public required DateTimeOffset LastAcknowledgedAt { get; init; }
|
|
|
|
/// <summary>
|
|
/// Total number of events acknowledged.
|
|
/// </summary>
|
|
public required long TotalAcknowledged { get; init; }
|
|
|
|
/// <summary>
|
|
/// When the consumer first started tracking this stream.
|
|
/// </summary>
|
|
public DateTimeOffset? FirstAcknowledgedAt { get; init; }
|
|
}
|