47 lines
2.4 KiB
C#
47 lines
2.4 KiB
C#
using Kbx.Shared.Integrations.Generated;
|
|
|
|
namespace Kbx.Shared.Integrations;
|
|
|
|
public sealed class KbxOutboxIntegrationDispatcher(
|
|
IKbxIntegrationAdapterRegistry adapters,
|
|
KbxIntegrationAttemptRepository attempts,
|
|
KbxPollyIntegrationPipeline pipelineFactory,
|
|
KbxIntegrationOperationsProjector operations)
|
|
{
|
|
public async Task<KbxIntegrationAttemptResult> DispatchAsync(KbxIntegrationMessage message, int durableAttempt, CancellationToken ct)
|
|
{
|
|
if (!KbxIntegrationCatalog.All.TryGetValue(message.IntegrationId, out var definition))
|
|
return new(false, KbxIntegrationFailureKind.Permanent, "INTEGRATION_NOT_REGISTERED", message.IntegrationId);
|
|
|
|
var attemptId = await attempts.StartAsync(message, durableAttempt, ct);
|
|
var pipeline = pipelineFactory.Build(
|
|
definition.ShortRetryAttempts,
|
|
TimeSpan.FromMilliseconds(definition.ShortRetryBaseDelayMs),
|
|
TimeSpan.FromMilliseconds(definition.TimeoutMs),
|
|
definition.CircuitFailureRatio,
|
|
TimeSpan.FromSeconds(definition.CircuitSamplingSeconds),
|
|
definition.CircuitMinimumThroughput,
|
|
TimeSpan.FromSeconds(definition.CircuitBreakSeconds));
|
|
|
|
KbxIntegrationAttemptResult result;
|
|
try
|
|
{
|
|
var adapter = adapters.GetRequired(message.IntegrationId);
|
|
result = await pipeline.ExecuteAsync(async token => await adapter.SendAsync(message, token), ct);
|
|
}
|
|
catch (Exception error)
|
|
{
|
|
result = new(false, KbxIntegrationFailureClassifier.Classify(error), error.GetType().Name, "외부 연계 호출이 완료되지 않았습니다.");
|
|
}
|
|
|
|
// A transient result is persisted and delegated to Hangfire for durable retry.
|
|
var state = result.Succeeded ? "delivered" : result.FailureKind == KbxIntegrationFailureKind.Transient ? "retrying" : "failed";
|
|
var next = state == "retrying" ? KbxDurableIntegrationRetryPlanner.NextAttemptAt(definition, durableAttempt, DateTimeOffset.UtcNow) : null;
|
|
await attempts.CompleteAsync(attemptId, result, state, next, ct);
|
|
if (result.Succeeded) await operations.OnDeliveredAsync(message, definition, ct);
|
|
else if (result.FailureKind == KbxIntegrationFailureKind.Permanent && definition.TerminalAction == "operations-exception")
|
|
await operations.OnPermanentFailureAsync(message, definition, result, ct);
|
|
return result;
|
|
}
|
|
}
|