Add a non-interrupting P14D boundary timer on the Beoordelen user task that fires an external-worker task (BeoordelingEscaleren) to the escalation end; wire the hosted BeoordelingEscalatiePump and register the escalation client/processor in DI. On timeout the still-open beoordeling is reassigned to teamlead (ADR-0015). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
50 lines
1.9 KiB
C#
50 lines
1.9 KiB
C#
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Big.Infrastructure;
|
|
|
|
/// <summary>
|
|
/// The hosted polling loop of the beoordeling-escalation worker (S-14, ADR-0015): on an interval it
|
|
/// resolves a scoped <see cref="BeoordelingEscalatieProcessor"/> and asks it to drain the parked
|
|
/// <c>BeoordelingEscaleren</c> jobs. A deliberately thin shell — all acquire/reassign/complete logic
|
|
/// lives in the processor, which is unit-tested; this class only owns the timer, the per-tick scope,
|
|
/// and loop resilience. Structurally identical to <see cref="OpenZaakJobPump"/>.
|
|
/// </summary>
|
|
public sealed class BeoordelingEscalatiePump(
|
|
IServiceScopeFactory scopeFactory,
|
|
FlowableOptions options,
|
|
ILogger<BeoordelingEscalatiePump> logger) : BackgroundService
|
|
{
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
using var scope = scopeFactory.CreateScope();
|
|
var processor = scope.ServiceProvider.GetRequiredService<BeoordelingEscalatieProcessor>();
|
|
await processor.PumpOnceAsync(options.MaxJobsPerPoll, stoppingToken);
|
|
}
|
|
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
|
{
|
|
break;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// A transient fault (e.g. Flowable briefly unreachable) must not kill the loop.
|
|
logger.LogError(ex, "BeoordelingEscaleren job poll failed; retrying after the poll interval.");
|
|
}
|
|
|
|
try
|
|
{
|
|
await Task.Delay(options.PollInterval, stoppingToken);
|
|
}
|
|
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|