feat: ship agent-first mission control v0.2.57
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
namespace Nexus.Api.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Continuously folds bounded Gateway chat/run events into the durable Nexus
|
||||
/// run projection. Re-processing is safe because per-run sequence cursors and
|
||||
/// persisted terminal/gap event ids reject duplicates.
|
||||
/// </summary>
|
||||
public sealed class OpenClawRunEventReconciler(
|
||||
IGatewayConnector connector,
|
||||
IServiceScopeFactory scopeFactory,
|
||||
ILogger<OpenClawRunEventReconciler> logger) : BackgroundService
|
||||
{
|
||||
private static readonly TimeSpan PollInterval = TimeSpan.FromMilliseconds(750);
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
string? cursor = null;
|
||||
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
var snapshot = connector.GetRecentEvents(500)
|
||||
.OrderBy(item => item.ReceivedAt)
|
||||
.ThenBy(item => item.Sequence)
|
||||
.ThenBy(OpenClawEventIdentity.Create, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
var startIndex = cursor is null
|
||||
? 0
|
||||
: snapshot.FindIndex(item =>
|
||||
string.Equals(
|
||||
OpenClawEventIdentity.Create(item),
|
||||
cursor,
|
||||
StringComparison.Ordinal)) + 1;
|
||||
if (startIndex <= 0 && cursor is not null)
|
||||
{
|
||||
// The bounded buffer rolled over. Re-process what remains;
|
||||
// run-level sequence cursors and persisted event ids dedupe it.
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
if (startIndex < snapshot.Count)
|
||||
{
|
||||
await using var scope = scopeFactory.CreateAsyncScope();
|
||||
var runs = scope.ServiceProvider.GetRequiredService<IOpenClawRunService>();
|
||||
foreach (var gatewayEvent in snapshot.Skip(startIndex))
|
||||
{
|
||||
await runs.ReconcileAsync(gatewayEvent, stoppingToken);
|
||||
cursor = OpenClawEventIdentity.Create(gatewayEvent);
|
||||
}
|
||||
}
|
||||
else if (snapshot.Count > 0)
|
||||
{
|
||||
cursor = OpenClawEventIdentity.Create(snapshot[^1]);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.LogWarning(
|
||||
exception,
|
||||
"Could not reconcile the latest OpenClaw run events; retrying without dropping the durable projection.");
|
||||
}
|
||||
|
||||
await Task.Delay(PollInterval, stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user