feat(notification-outbox): add NotificationOutboxOptions and delivery adapter abstraction
This commit is contained in:
40
src/ScadaLink.NotificationOutbox/Delivery/DeliveryOutcome.cs
Normal file
40
src/ScadaLink.NotificationOutbox/Delivery/DeliveryOutcome.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
namespace ScadaLink.NotificationOutbox.Delivery;
|
||||
|
||||
/// <summary>
|
||||
/// Classification of a single delivery attempt. Transient failures are eligible for
|
||||
/// retry; permanent failures are terminal and not retried.
|
||||
/// </summary>
|
||||
public enum DeliveryResult
|
||||
{
|
||||
/// <summary>The notification was delivered successfully.</summary>
|
||||
Success,
|
||||
|
||||
/// <summary>Delivery failed for a transient reason and may succeed on retry.</summary>
|
||||
TransientFailure,
|
||||
|
||||
/// <summary>Delivery failed for a permanent reason and must not be retried.</summary>
|
||||
PermanentFailure
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of a delivery attempt produced by an <see cref="INotificationDeliveryAdapter"/>.
|
||||
/// </summary>
|
||||
/// <param name="Result">The classification of the attempt.</param>
|
||||
/// <param name="ResolvedTargets">
|
||||
/// The concrete delivery targets used, snapshotted for audit. Set only on success.
|
||||
/// </param>
|
||||
/// <param name="Error">A human-readable failure description. Set only on failure.</param>
|
||||
public record DeliveryOutcome(DeliveryResult Result, string? ResolvedTargets, string? Error)
|
||||
{
|
||||
/// <summary>Creates a successful outcome carrying the resolved delivery targets.</summary>
|
||||
public static DeliveryOutcome Success(string resolvedTargets) =>
|
||||
new(DeliveryResult.Success, resolvedTargets, null);
|
||||
|
||||
/// <summary>Creates a transient-failure outcome carrying an error description.</summary>
|
||||
public static DeliveryOutcome Transient(string error) =>
|
||||
new(DeliveryResult.TransientFailure, null, error);
|
||||
|
||||
/// <summary>Creates a permanent-failure outcome carrying an error description.</summary>
|
||||
public static DeliveryOutcome Permanent(string error) =>
|
||||
new(DeliveryResult.PermanentFailure, null, error);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using ScadaLink.Commons.Entities.Notifications;
|
||||
using ScadaLink.Commons.Types.Enums;
|
||||
|
||||
namespace ScadaLink.NotificationOutbox.Delivery;
|
||||
|
||||
/// <summary>
|
||||
/// Channel-specific delivery strategy for outbox notifications. Each adapter handles
|
||||
/// a single <see cref="NotificationType"/>; the outbox dispatcher selects the adapter
|
||||
/// matching a notification's type.
|
||||
/// </summary>
|
||||
public interface INotificationDeliveryAdapter
|
||||
{
|
||||
/// <summary>The notification channel this adapter delivers.</summary>
|
||||
NotificationType Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts delivery of the given notification and reports the classified outcome.
|
||||
/// </summary>
|
||||
/// <param name="notification">The notification to deliver.</param>
|
||||
/// <param name="cancellationToken">Token used to cancel the delivery attempt.</param>
|
||||
/// <returns>The outcome of the delivery attempt.</returns>
|
||||
Task<DeliveryOutcome> DeliverAsync(Notification notification, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace ScadaLink.NotificationOutbox;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration options for the Notification Outbox component: dispatch cadence,
|
||||
/// batch sizing, stuck-message detection, terminal retention, and KPI windowing.
|
||||
/// </summary>
|
||||
public class NotificationOutboxOptions
|
||||
{
|
||||
/// <summary>Interval between dispatch sweeps that pick up pending notifications for delivery.</summary>
|
||||
public TimeSpan DispatchInterval { get; set; } = TimeSpan.FromSeconds(10);
|
||||
|
||||
/// <summary>Maximum number of notifications claimed for delivery in a single dispatch sweep.</summary>
|
||||
public int DispatchBatchSize { get; set; } = 100;
|
||||
|
||||
/// <summary>Age past which an in-progress notification is considered stuck and re-claimed.</summary>
|
||||
public TimeSpan StuckAgeThreshold { get; set; } = TimeSpan.FromMinutes(10);
|
||||
|
||||
/// <summary>Retention period for notifications in a terminal state before they are purged.</summary>
|
||||
public TimeSpan TerminalRetention { get; set; } = TimeSpan.FromDays(365);
|
||||
|
||||
/// <summary>Interval between background purge sweeps of terminal notifications.</summary>
|
||||
public TimeSpan PurgeInterval { get; set; } = TimeSpan.FromDays(1);
|
||||
|
||||
/// <summary>Trailing window used to compute the delivered-notifications throughput KPI.</summary>
|
||||
public TimeSpan DeliveredKpiWindow { get; set; } = TimeSpan.FromMinutes(1);
|
||||
}
|
||||
Reference in New Issue
Block a user