up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Reachability Corpus Validation / validate-corpus (push) Has been cancelled
Reachability Corpus Validation / validate-ground-truths (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Reachability Corpus Validation / determinism-check (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Reachability Corpus Validation / validate-corpus (push) Has been cancelled
Reachability Corpus Validation / validate-ground-truths (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Reachability Corpus Validation / determinism-check (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
using StellaOps.Signals.Models;
|
||||
|
||||
namespace StellaOps.Signals.Persistence;
|
||||
|
||||
/// <summary>
|
||||
/// Repository for persisting and querying proc snapshot documents.
|
||||
/// </summary>
|
||||
public interface IProcSnapshotRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Upsert a proc snapshot document.
|
||||
/// </summary>
|
||||
Task<ProcSnapshotDocument> UpsertAsync(ProcSnapshotDocument document, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Get a proc snapshot by ID.
|
||||
/// </summary>
|
||||
Task<ProcSnapshotDocument?> GetByIdAsync(string id, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Get all proc snapshots for a specific image digest.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<ProcSnapshotDocument>> GetByImageDigestAsync(
|
||||
string tenant,
|
||||
string imageDigest,
|
||||
int limit = 100,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get the most recent proc snapshot for an image digest and runtime type.
|
||||
/// </summary>
|
||||
Task<ProcSnapshotDocument?> GetLatestAsync(
|
||||
string tenant,
|
||||
string imageDigest,
|
||||
string runtimeType,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Delete expired proc snapshots.
|
||||
/// </summary>
|
||||
Task<int> DeleteExpiredAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Collections.Concurrent;
|
||||
using StellaOps.Signals.Models;
|
||||
|
||||
namespace StellaOps.Signals.Persistence;
|
||||
|
||||
/// <summary>
|
||||
/// In-memory implementation of <see cref="IProcSnapshotRepository"/> for testing and development.
|
||||
/// </summary>
|
||||
public sealed class InMemoryProcSnapshotRepository : IProcSnapshotRepository
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, ProcSnapshotDocument> _documents = new(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public InMemoryProcSnapshotRepository(TimeProvider timeProvider)
|
||||
{
|
||||
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
}
|
||||
|
||||
public Task<ProcSnapshotDocument> UpsertAsync(ProcSnapshotDocument document, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(document);
|
||||
|
||||
_documents[document.Id] = document;
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
|
||||
public Task<ProcSnapshotDocument?> GetByIdAsync(string id, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(id);
|
||||
|
||||
_documents.TryGetValue(id, out var document);
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<ProcSnapshotDocument>> GetByImageDigestAsync(
|
||||
string tenant,
|
||||
string imageDigest,
|
||||
int limit = 100,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(tenant);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(imageDigest);
|
||||
|
||||
var normalizedDigest = imageDigest.ToLowerInvariant();
|
||||
var results = _documents.Values
|
||||
.Where(d => string.Equals(d.Tenant, tenant, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(d.ImageDigest, normalizedDigest, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderByDescending(d => d.CapturedAt)
|
||||
.Take(limit)
|
||||
.ToList();
|
||||
|
||||
return Task.FromResult<IReadOnlyList<ProcSnapshotDocument>>(results);
|
||||
}
|
||||
|
||||
public Task<ProcSnapshotDocument?> GetLatestAsync(
|
||||
string tenant,
|
||||
string imageDigest,
|
||||
string runtimeType,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(tenant);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(imageDigest);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(runtimeType);
|
||||
|
||||
var normalizedDigest = imageDigest.ToLowerInvariant();
|
||||
var result = _documents.Values
|
||||
.Where(d => string.Equals(d.Tenant, tenant, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(d.ImageDigest, normalizedDigest, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(d.RuntimeType, runtimeType, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderByDescending(d => d.CapturedAt)
|
||||
.FirstOrDefault();
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public Task<int> DeleteExpiredAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var expiredIds = _documents
|
||||
.Where(kv => kv.Value.ExpiresAt.HasValue && kv.Value.ExpiresAt.Value < now)
|
||||
.Select(kv => kv.Key)
|
||||
.ToList();
|
||||
|
||||
var deletedCount = 0;
|
||||
foreach (var id in expiredIds)
|
||||
{
|
||||
if (_documents.TryRemove(id, out _))
|
||||
{
|
||||
deletedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(deletedCount);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user