Files
KArtSell.Aegis/docs/Design/kbx-foundation-v36/backend/Shared/Integrations/KbxOutboxIntegrationDispatcher.cs
T

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;
}
}