Files
git.stella-ops.org/src/__Libraries/StellaOps.Provcache/ProvcacheService.Get.cs

101 lines
4.1 KiB
C#

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace StellaOps.Provcache;
public sealed partial class ProvcacheService
{
/// <inheritdoc />
public async Task<ProvcacheServiceResult> GetAsync(
string veriKey,
bool bypassCache = false,
CancellationToken cancellationToken = default)
{
ArgumentException.ThrowIfNullOrWhiteSpace(veriKey);
if (bypassCache && _options.AllowCacheBypass)
{
_logger.LogDebug("Cache bypass requested for VeriKey {VeriKey}", veriKey);
return ProvcacheServiceResult.Bypassed();
}
var sw = Stopwatch.StartNew();
using var activity = ProvcacheTelemetry.StartGetActivity(veriKey);
try
{
var result = await _store.GetAsync(veriKey, cancellationToken).ConfigureAwait(false);
sw.Stop();
RecordMetrics(result.IsHit, sw.Elapsed.TotalMilliseconds);
if (result.IsHit && result.Entry is not null)
{
if (result.Entry.ExpiresAt <= _timeProvider.GetUtcNow())
{
_logger.LogDebug("Cache entry for VeriKey {VeriKey} is expired", veriKey);
ProvcacheTelemetry.RecordRequest("get", "expired");
return ProvcacheServiceResult.Expired(result.Entry, sw.Elapsed.TotalMilliseconds);
}
_logger.LogDebug(
"Cache hit for VeriKey {VeriKey} from {Source} in {ElapsedMs}ms",
veriKey,
result.Source,
sw.Elapsed.TotalMilliseconds);
ProvcacheTelemetry.MarkCacheHit(activity, result.Source ?? "valkey");
ProvcacheTelemetry.RecordHit(result.Source ?? "valkey");
ProvcacheTelemetry.RecordRequest("get", ProvcacheTelemetry.ResultHit);
ProvcacheTelemetry.RecordLatency("get", sw.Elapsed);
return ProvcacheServiceResult.Hit(result.Entry, result.Source!, sw.Elapsed.TotalMilliseconds);
}
var dbEntry = await _repository.GetAsync(veriKey, cancellationToken).ConfigureAwait(false);
sw.Stop();
if (dbEntry is not null)
{
if (dbEntry.ExpiresAt <= _timeProvider.GetUtcNow())
{
_logger.LogDebug("Database entry for VeriKey {VeriKey} is expired", veriKey);
ProvcacheTelemetry.RecordRequest("get", "expired");
return ProvcacheServiceResult.Expired(dbEntry, sw.Elapsed.TotalMilliseconds);
}
await _store.SetAsync(dbEntry, cancellationToken).ConfigureAwait(false);
_logger.LogDebug(
"Cache backfill for VeriKey {VeriKey} from postgres in {ElapsedMs}ms",
veriKey,
sw.Elapsed.TotalMilliseconds);
ProvcacheTelemetry.MarkCacheHit(activity, "postgres");
ProvcacheTelemetry.RecordHit("postgres");
ProvcacheTelemetry.RecordRequest("get", ProvcacheTelemetry.ResultHit);
ProvcacheTelemetry.RecordLatency("get", sw.Elapsed);
return ProvcacheServiceResult.Hit(dbEntry, "postgres", sw.Elapsed.TotalMilliseconds);
}
ProvcacheTelemetry.MarkCacheMiss(activity);
ProvcacheTelemetry.RecordMiss();
ProvcacheTelemetry.RecordRequest("get", ProvcacheTelemetry.ResultMiss);
ProvcacheTelemetry.RecordLatency("get", sw.Elapsed);
_logger.LogDebug("Cache miss for VeriKey {VeriKey} in {ElapsedMs}ms", veriKey, sw.Elapsed.TotalMilliseconds);
return ProvcacheServiceResult.Miss(sw.Elapsed.TotalMilliseconds);
}
catch (Exception ex)
{
ProvcacheTelemetry.MarkError(activity, ex.Message);
ProvcacheTelemetry.RecordRequest("get", ProvcacheTelemetry.ResultError);
_logger.LogError(ex, "Error getting cache entry for VeriKey {VeriKey}", veriKey);
return ProvcacheServiceResult.Miss(sw.Elapsed.TotalMilliseconds);
}
}
}