feat(engine): WebhookRouter (TCS + first-write-wins + timeout)

This commit is contained in:
Claude
2026-08-28 14:56:52 +00:00
parent 159102e27e
commit eabd6f175d
3 changed files with 79 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
using System.Collections.Concurrent;
namespace VolcanicCore.Api.Engine;
public sealed record WebResponsePayload(int StatusCode, string Body, string ContentType);
public sealed class WebhookRouter
{
private sealed record Entry(
TaskCompletionSource<WebResponsePayload?> Tcs,
CancellationTokenSource Timeout);
private readonly ConcurrentDictionary<Guid, Entry> _pending = new();
public Task<WebResponsePayload?> Register(Guid id, TimeSpan timeout)
{
var tcs = new TaskCompletionSource<WebResponsePayload?>(TaskCreationOptions.RunContinuationsAsynchronously);
var cts = new CancellationTokenSource(timeout);
cts.Token.Register(() =>
{
if (_pending.TryRemove(id, out _))
tcs.TrySetResult(null); // timeout fires as null
});
_pending[id] = new Entry(tcs, cts);
return tcs.Task;
}
// Returns true iff this call was the first to resolve the channel.
public bool Resolve(Guid id, WebResponsePayload payload)
{
if (!_pending.TryRemove(id, out var entry)) return false;
entry.Timeout.Dispose();
return entry.Tcs.TrySetResult(payload);
}
}

View File

@@ -117,6 +117,8 @@ builder.Services.AddSingleton<ConnectionInstanceRegistry>();
builder.Services.AddSingleton<IConnectionInstanceRegistry>(sp =>
sp.GetRequiredService<ConnectionInstanceRegistry>());
builder.Services.AddSingleton<WebhookRouter>();
var app = builder.Build();
// Apply migrations at boot.