fix(notifications): deterministic lowest-Id SMTP config selection (+ multi-row warning); atomic OAuth2 token cache entry

Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
Joseph Doherty
2026-07-10 04:14:14 -04:00
parent eb7a913d22
commit 39e1ca3eae
4 changed files with 74 additions and 11 deletions
@@ -73,12 +73,22 @@ public sealed class EmailNotificationDeliveryAdapter : INotificationDeliveryAdap
}
var smtpConfigs = await _repository.GetAllSmtpConfigurationsAsync(cancellationToken);
var smtpConfig = smtpConfigs.FirstOrDefault();
// Deterministic pick: the lowest-Id row wins regardless of repository order,
// so every node/attempt agrees on the same configuration (arch-review S7).
var smtpConfig = smtpConfigs.OrderBy(c => c.Id).FirstOrDefault();
if (smtpConfig == null)
{
return DeliveryOutcome.Permanent("No SMTP configuration available");
}
if (smtpConfigs.Count > 1)
{
_logger.LogWarning(
"Multiple SMTP configurations exist; using the lowest-Id row ({Id}). "
+ "Enforce a single row or delete extras.",
smtpConfig.Id);
}
// An unknown TLS mode is a configuration error that retrying cannot fix —
// surface it as a permanent failure (SMTP TLS validation policy).
SmtpTlsMode tlsMode;
@@ -437,7 +437,7 @@ public class NotificationOutboxActor : ReceiveActor, IWithTimers
}
/// <summary>
/// Resolves the SMTP-derived retry policy from the first SMTP configuration row. When no
/// Resolves the SMTP-derived retry policy from the lowest-Id SMTP configuration row. When no
/// SMTP configuration exists, falls back to the conservative default constants — delivery
/// itself will permanently fail in that case, so the policy only acts as a guard.
/// </summary>
@@ -445,12 +445,22 @@ public class NotificationOutboxActor : ReceiveActor, IWithTimers
INotificationRepository notificationRepository)
{
var configurations = await notificationRepository.GetAllSmtpConfigurationsAsync();
var configuration = configurations.Count > 0 ? configurations[0] : null;
// Deterministic pick: the lowest-Id row wins regardless of repository order, so the
// retry policy resolves the same way the delivery adapter selects its config (S7).
var configuration = configurations.OrderBy(c => c.Id).FirstOrDefault();
if (configuration is null)
{
return new RetryPolicy(FallbackMaxRetries, FallbackRetryDelay);
}
if (configurations.Count > 1)
{
_logger.LogWarning(
"Multiple SMTP configurations exist; using the lowest-Id row ({Id}). "
+ "Enforce a single row or delete extras.",
configuration.Id);
}
return ClampRetryPolicy(
nameof(SmtpConfiguration), configuration.MaxRetries, configuration.RetryDelay);
}