Files
git.stella-ops.org/src/__Libraries/StellaOps.Provcache/Events/FeedEpochAdvancedEvent.cs
2026-01-13 18:53:39 +02:00

132 lines
4.7 KiB
C#

using StellaOps.Determinism;
namespace StellaOps.Provcache.Events;
/// <summary>
/// Event published when an advisory feed advances to a new epoch.
/// Provcache subscribers use this to invalidate cache entries
/// that were computed against older feed epochs.
/// </summary>
/// <remarks>
/// Stream name: <c>stellaops:events:feed-epoch-advanced</c>
/// </remarks>
public sealed record FeedEpochAdvancedEvent
{
/// <summary>
/// Stream name for feed epoch events.
/// </summary>
public const string StreamName = "stellaops:events:feed-epoch-advanced";
/// <summary>
/// Event type identifier for serialization.
/// </summary>
public const string EventType = "feed.epoch.advanced.v1";
/// <summary>
/// Unique identifier for this event instance.
/// </summary>
public required Guid EventId { get; init; }
/// <summary>
/// Timestamp when the event occurred (UTC).
/// </summary>
public required DateTimeOffset Timestamp { get; init; }
/// <summary>
/// The feed identifier (e.g., "cve", "ghsa", "osv", "redhat-oval").
/// </summary>
public required string FeedId { get; init; }
/// <summary>
/// The previous epoch identifier.
/// Format varies by feed (e.g., "2024-12-24T12:00:00Z", "v2024.52").
/// </summary>
public required string PreviousEpoch { get; init; }
/// <summary>
/// The new epoch identifier.
/// </summary>
public required string NewEpoch { get; init; }
/// <summary>
/// When the new epoch became effective.
/// Cache entries with feed_epoch older than this should be invalidated.
/// </summary>
public required DateTimeOffset EffectiveAt { get; init; }
/// <summary>
/// Number of advisories added in this epoch (for metrics).
/// </summary>
public int? AdvisoriesAdded { get; init; }
/// <summary>
/// Number of advisories modified in this epoch (for metrics).
/// </summary>
public int? AdvisoriesModified { get; init; }
/// <summary>
/// Number of advisories withdrawn in this epoch (for metrics).
/// </summary>
public int? AdvisoriesWithdrawn { get; init; }
/// <summary>
/// Tenant ID if multi-tenant (null for global feeds).
/// </summary>
public string? TenantId { get; init; }
/// <summary>
/// Correlation ID for distributed tracing.
/// </summary>
public string? CorrelationId { get; init; }
/// <summary>
/// Creates a new FeedEpochAdvancedEvent.
/// </summary>
/// <param name="feedId">The feed identifier.</param>
/// <param name="previousEpoch">The previous epoch identifier.</param>
/// <param name="newEpoch">The new epoch identifier.</param>
/// <param name="effectiveAt">When the new epoch became effective.</param>
/// <param name="advisoriesAdded">Number of advisories added (for metrics).</param>
/// <param name="advisoriesModified">Number of advisories modified (for metrics).</param>
/// <param name="advisoriesWithdrawn">Number of advisories withdrawn (for metrics).</param>
/// <param name="tenantId">Tenant ID if multi-tenant.</param>
/// <param name="correlationId">Correlation ID for tracing.</param>
/// <param name="eventId">Optional event ID (defaults to new GUID).</param>
/// <param name="timestamp">Optional timestamp (defaults to current UTC time).</param>
/// <param name="guidProvider">Optional GUID provider for deterministic IDs.</param>
/// <param name="timeProvider">Optional time provider for deterministic timestamps.</param>
public static FeedEpochAdvancedEvent Create(
string feedId,
string previousEpoch,
string newEpoch,
DateTimeOffset effectiveAt,
int? advisoriesAdded = null,
int? advisoriesModified = null,
int? advisoriesWithdrawn = null,
string? tenantId = null,
string? correlationId = null,
Guid? eventId = null,
DateTimeOffset? timestamp = null,
IGuidProvider? guidProvider = null,
TimeProvider? timeProvider = null)
{
var guidSource = guidProvider ?? SystemGuidProvider.Instance;
var timeSource = timeProvider ?? TimeProvider.System;
return new FeedEpochAdvancedEvent
{
EventId = eventId ?? guidSource.NewGuid(),
Timestamp = timestamp ?? timeSource.GetUtcNow(),
FeedId = feedId,
PreviousEpoch = previousEpoch,
NewEpoch = newEpoch,
EffectiveAt = effectiveAt,
AdvisoriesAdded = advisoriesAdded,
AdvisoriesModified = advisoriesModified,
AdvisoriesWithdrawn = advisoriesWithdrawn,
TenantId = tenantId,
CorrelationId = correlationId
};
}
}