Added Smtp reconnect on connection loss
Some checks failed
Docker Release / build (push) Has been cancelled
GitHub Release / Generate Release (push) Has been cancelled

This commit is contained in:
Mia Rose Winter 2024-04-08 11:46:54 +02:00
parent 8563391584
commit 1193d76838
Signed by: miawinter
GPG key ID: 4B6F6A83178F595E
2 changed files with 32 additions and 5 deletions

View file

@ -4,7 +4,7 @@ public interface IEmailService : IAsyncDisposable {
ValueTask ConnectAsync(CancellationToken cancellation);
ValueTask DisconnectAsync(CancellationToken cancellation);
ValueTask SendEmailAsync(IEmail email);
ValueTask SendEmailAsync(IEmail email, CancellationToken cancellation = default);
}
public sealed class NoOpEmailService : IEmailService {
@ -12,5 +12,5 @@ public sealed class NoOpEmailService : IEmailService {
public ValueTask ConnectAsync(CancellationToken cancellation) => ValueTask.CompletedTask;
public ValueTask DisconnectAsync(CancellationToken cancellation) => ValueTask.CompletedTask;
public ValueTask SendEmailAsync(IEmail email) => ValueTask.CompletedTask;
public ValueTask SendEmailAsync(IEmail email, CancellationToken cancellation = default) => ValueTask.CompletedTask;
}

View file

@ -1,4 +1,5 @@
using MailKit.Net.Smtp;
using MailKit;
using MailKit.Net.Smtp;
using MailKit.Security;
using Microsoft.Extensions.Options;
using MimeKit;
@ -43,7 +44,7 @@ public class SmtpEmailService(ILogger<SmtpEmailService> logger, IOptions<EmailCo
Client = null;
}
public async ValueTask SendEmailAsync(IEmail email) {
public async ValueTask SendEmailAsync(IEmail email, CancellationToken cancellation = default) {
if (Client is null) throw new ApplicationException("Not connected.");
var message = new MimeMessage {
@ -66,10 +67,13 @@ public class SmtpEmailService(ILogger<SmtpEmailService> logger, IOptions<EmailCo
int retryCount = 0;
while (retryCount < 3) {
try {
await Client.SendAsync(message);
await Client.SendAsync(message, cancellation);
Logger.LogInformation("Successfully send mail to {email} (subject: {subject}).",
email.ReceiverEmail, email.Subject);
return;
} catch (ServiceNotConnectedException ex) {
Logger.LogWarning(ex, "Not connected, attempting reconnect.");
if (!await TryReconnect(cancellation)) throw;
} catch (Exception ex) {
retryCount++;
Logger.LogWarning(ex, "Error sending E-Mail to {email}. Try: {RetryCount}.",
@ -80,4 +84,27 @@ public class SmtpEmailService(ILogger<SmtpEmailService> logger, IOptions<EmailCo
// throw new EmailNotSendException();
Logger.LogError("Giving up");
}
private async ValueTask<bool> TryReconnect(CancellationToken cancellation) {
int reconnectCount = 0;
while (true) {
try {
await DisconnectAsync(cancellation);
await ConnectAsync(cancellation);
return true;
} catch (Exception ex1) {
reconnectCount++;
// 2^11 = 2048 seconds ~= 34 minutes
if (reconnectCount <= 11) {
// 2 4 6 8 16 32 64... seconds
int waitTime = (int)Math.Pow(2, reconnectCount);
Logger.LogError(ex1, "Reconnect failed, Try: {ReconnectTry}. Will wait {ReconnectWaitTime} Seconds for next attempt.", reconnectCount, waitTime);
await Task.Delay(TimeSpan.FromSeconds(waitTime), cancellation);
} else {
Logger.LogCritical(ex1, "Reconnect retry count exceeded, giving up.");
return false;
}
}
}
}
}