feat(usage): hold the last good TokenTracker export fail-open

This commit is contained in:
mika kuns
2026-08-24 13:36:59 +02:00
parent 2fca0cc4d3
commit 580d4e0717
2 changed files with 121 additions and 0 deletions
@@ -0,0 +1,55 @@
namespace ClaudeDo.Worker.Usage.TokenTracker;
/// <summary>
/// Threadsafe holder for the last successful export. Mirrors <see cref="UsageState"/>: a failed
/// fetch never overwrites a good export, it only records <see cref="LastError"/>.
/// </summary>
public sealed class TokenTrackerState
{
private readonly object _lock = new();
private TokenTrackerExport? _export;
private DateTime? _lastAttemptUtc;
private string? _lastError;
public TokenTrackerExport? Export
{
get { lock (_lock) return _export; }
}
public DateTime? LastAttemptUtc
{
get { lock (_lock) return _lastAttemptUtc; }
}
public string? LastError
{
get { lock (_lock) return _lastError; }
}
public void ReportSuccess(TokenTrackerExport export)
{
lock (_lock)
{
_export = export;
_lastAttemptUtc = export.FetchedAtUtc;
_lastError = null;
}
}
public void ReportFailure(string error, DateTime attemptedAtUtc)
{
lock (_lock)
{
_lastAttemptUtc = attemptedAtUtc;
_lastError = error;
}
}
public bool IsOlderThan(TimeSpan maxAge, DateTime nowUtc)
{
lock (_lock)
{
return _export is null || nowUtc - _export.FetchedAtUtc > maxAge;
}
}
}