Files
git.stella-ops.org/src/Concelier/__Libraries/StellaOps.Concelier.Cache.Valkey/IAdvisoryCacheService.cs
2025-12-25 23:10:09 +02:00

156 lines
6.4 KiB
C#

// -----------------------------------------------------------------------------
// IAdvisoryCacheService.cs
// Sprint: SPRINT_8200_0013_0001_GW_valkey_advisory_cache
// Task: VCACHE-8200-010
// Description: Interface for Valkey-based canonical advisory caching
// -----------------------------------------------------------------------------
using StellaOps.Concelier.Core.Canonical;
namespace StellaOps.Concelier.Cache.Valkey;
/// <summary>
/// Valkey-based cache for canonical advisories.
/// Provides read-through caching with TTL based on interest score.
/// </summary>
public interface IAdvisoryCacheService
{
// === Read Operations ===
/// <summary>
/// Get canonical advisory by merge hash (cache-first).
/// </summary>
/// <param name="mergeHash">The merge hash identifying the canonical.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The cached advisory, or null if not found.</returns>
Task<CanonicalAdvisory?> GetAsync(string mergeHash, CancellationToken cancellationToken = default);
/// <summary>
/// Get canonical advisories by PURL (uses index).
/// </summary>
/// <param name="purl">The PURL to lookup.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>List of advisories affecting this PURL.</returns>
Task<IReadOnlyList<CanonicalAdvisory>> GetByPurlAsync(string purl, CancellationToken cancellationToken = default);
/// <summary>
/// Get canonical advisory by CVE (uses mapping).
/// </summary>
/// <param name="cve">The CVE identifier.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The primary canonical for this CVE, or null.</returns>
Task<CanonicalAdvisory?> GetByCveAsync(string cve, CancellationToken cancellationToken = default);
/// <summary>
/// Get hot advisories (top N by interest score).
/// </summary>
/// <param name="limit">Maximum number to return.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>List of hot advisories in descending score order.</returns>
Task<IReadOnlyList<CanonicalAdvisory>> GetHotAsync(int limit = 100, CancellationToken cancellationToken = default);
// === Write Operations ===
/// <summary>
/// Cache canonical advisory with TTL based on interest score.
/// </summary>
/// <param name="advisory">The advisory to cache.</param>
/// <param name="interestScore">Optional interest score (0.0-1.0) for TTL calculation.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task SetAsync(CanonicalAdvisory advisory, double? interestScore = null, CancellationToken cancellationToken = default);
/// <summary>
/// Invalidate cached advisory.
/// </summary>
/// <param name="mergeHash">The merge hash to invalidate.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task InvalidateAsync(string mergeHash, CancellationToken cancellationToken = default);
/// <summary>
/// Update interest score (affects TTL and hot set membership).
/// </summary>
/// <param name="mergeHash">The merge hash to update.</param>
/// <param name="score">The new interest score (0.0-1.0).</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task UpdateScoreAsync(string mergeHash, double score, CancellationToken cancellationToken = default);
// === Index Operations ===
/// <summary>
/// Add merge hash to PURL index.
/// </summary>
/// <param name="purl">The PURL to index.</param>
/// <param name="mergeHash">The merge hash to add.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task IndexPurlAsync(string purl, string mergeHash, CancellationToken cancellationToken = default);
/// <summary>
/// Remove merge hash from PURL index.
/// </summary>
/// <param name="purl">The PURL to unindex.</param>
/// <param name="mergeHash">The merge hash to remove.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task UnindexPurlAsync(string purl, string mergeHash, CancellationToken cancellationToken = default);
/// <summary>
/// Set CVE to merge hash mapping.
/// </summary>
/// <param name="cve">The CVE identifier.</param>
/// <param name="mergeHash">The canonical merge hash.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task IndexCveAsync(string cve, string mergeHash, CancellationToken cancellationToken = default);
// === Maintenance ===
/// <summary>
/// Warm cache with hot advisories from database.
/// </summary>
/// <param name="limit">Maximum number of advisories to preload.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task WarmupAsync(int limit = 1000, CancellationToken cancellationToken = default);
/// <summary>
/// Get cache statistics.
/// </summary>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Current cache statistics.</returns>
Task<CacheStatistics> GetStatisticsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Check if the cache service is healthy.
/// </summary>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>True if the cache is reachable and operational.</returns>
Task<bool> IsHealthyAsync(CancellationToken cancellationToken = default);
}
/// <summary>
/// Cache statistics for monitoring and debugging.
/// </summary>
public sealed record CacheStatistics
{
/// <summary>Total cache hits.</summary>
public long Hits { get; init; }
/// <summary>Total cache misses.</summary>
public long Misses { get; init; }
/// <summary>Cache hit rate (0.0-1.0).</summary>
public double HitRate => Hits + Misses > 0 ? (double)Hits / (Hits + Misses) : 0;
/// <summary>Current size of the hot advisory set.</summary>
public long HotSetSize { get; init; }
/// <summary>Approximate total cached advisories.</summary>
public long TotalCachedAdvisories { get; init; }
/// <summary>When the cache was last warmed up.</summary>
public DateTimeOffset? LastWarmup { get; init; }
/// <summary>Whether the cache service is currently healthy.</summary>
public bool IsHealthy { get; init; }
/// <summary>Valkey server info string.</summary>
public string? ServerInfo { get; init; }
}