Added Smtp reconnect on connection loss
This commit is contained in:
parent
8563391584
commit
1193d76838
|
@ -4,7 +4,7 @@ public interface IEmailService : IAsyncDisposable {
|
||||||
ValueTask ConnectAsync(CancellationToken cancellation);
|
ValueTask ConnectAsync(CancellationToken cancellation);
|
||||||
ValueTask DisconnectAsync(CancellationToken cancellation);
|
ValueTask DisconnectAsync(CancellationToken cancellation);
|
||||||
|
|
||||||
ValueTask SendEmailAsync(IEmail email);
|
ValueTask SendEmailAsync(IEmail email, CancellationToken cancellation = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class NoOpEmailService : IEmailService {
|
public sealed class NoOpEmailService : IEmailService {
|
||||||
|
@ -12,5 +12,5 @@ public sealed class NoOpEmailService : IEmailService {
|
||||||
|
|
||||||
public ValueTask ConnectAsync(CancellationToken cancellation) => ValueTask.CompletedTask;
|
public ValueTask ConnectAsync(CancellationToken cancellation) => ValueTask.CompletedTask;
|
||||||
public ValueTask DisconnectAsync(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;
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using MailKit.Net.Smtp;
|
using MailKit;
|
||||||
|
using MailKit.Net.Smtp;
|
||||||
using MailKit.Security;
|
using MailKit.Security;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
|
@ -43,7 +44,7 @@ public class SmtpEmailService(ILogger<SmtpEmailService> logger, IOptions<EmailCo
|
||||||
Client = null;
|
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.");
|
if (Client is null) throw new ApplicationException("Not connected.");
|
||||||
|
|
||||||
var message = new MimeMessage {
|
var message = new MimeMessage {
|
||||||
|
@ -66,10 +67,13 @@ public class SmtpEmailService(ILogger<SmtpEmailService> logger, IOptions<EmailCo
|
||||||
int retryCount = 0;
|
int retryCount = 0;
|
||||||
while (retryCount < 3) {
|
while (retryCount < 3) {
|
||||||
try {
|
try {
|
||||||
await Client.SendAsync(message);
|
await Client.SendAsync(message, cancellation);
|
||||||
Logger.LogInformation("Successfully send mail to {email} (subject: {subject}).",
|
Logger.LogInformation("Successfully send mail to {email} (subject: {subject}).",
|
||||||
email.ReceiverEmail, email.Subject);
|
email.ReceiverEmail, email.Subject);
|
||||||
return;
|
return;
|
||||||
|
} catch (ServiceNotConnectedException ex) {
|
||||||
|
Logger.LogWarning(ex, "Not connected, attempting reconnect.");
|
||||||
|
if (!await TryReconnect(cancellation)) throw;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
retryCount++;
|
retryCount++;
|
||||||
Logger.LogWarning(ex, "Error sending E-Mail to {email}. Try: {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();
|
// throw new EmailNotSendException();
|
||||||
Logger.LogError("Giving up");
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue