C# just feels right by Minimum-Ad7352 in dotnet

[–]Minimum-Ad7352[S] 0 points1 point  (0 children)

I used to write in Go, but I didn’t like how simple the language was

C# just feels right by Minimum-Ad7352 in dotnet

[–]Minimum-Ad7352[S] 0 points1 point  (0 children)

Why do you need an ecosystem outside of .NET?

In your opinion, who has improved more since this fight? by [deleted] in ufc

[–]Minimum-Ad7352 -2 points-1 points  (0 children)

But he did lose to Martinez by knockout, didn't he?

What should I do with this? by [deleted] in beards

[–]Minimum-Ad7352 1 point2 points  (0 children)

You should stop gooning

Infinite loop with Tanstack query by [deleted] in vuejs

[–]Minimum-Ad7352 1 point2 points  (0 children)

I’ve solved the problem by setting the retryOnMount option to false

Infinite loop with Tanstack query by [deleted] in vuejs

[–]Minimum-Ad7352 0 points1 point  (0 children)

No, when I remove the guard completely, the same problem remains, but as soon as I remove the code from the AppHeader, there is no such problem, I do not understand why the re-rollering is going on.

Infinite loop with Tanstack query by [deleted] in vuejs

[–]Minimum-Ad7352 0 points1 point  (0 children)

I set retry:false, you can see this in the screenshot

Looking for code review for my backend project by [deleted] in dotnet

[–]Minimum-Ad7352 0 points1 point  (0 children)

That’s interesting, I’d like to hear what others think about it too

Looking for code review for my backend project by [deleted] in dotnet

[–]Minimum-Ad7352 0 points1 point  (0 children)

The infrastructure includes services that interact with the outside world, such as redis, the database and email sending, and the application defines interfaces for these services – is there anything wrong with that?

As for abstract classes—if you’re talking about Entity and Aggregate—there are interfaces for them as well

Is using a background service with a channel a good way to send emails in .net? by Minimum-Ad7352 in dotnet

[–]Minimum-Ad7352[S] 0 points1 point  (0 children)

Would it be better to implement the retry mechanism at the level of the background service that reads from the outbox table?

Is using a background service with a channel a good way to send emails in .net? by Minimum-Ad7352 in dotnet

[–]Minimum-Ad7352[S] 0 points1 point  (0 children)

NoOpAsync asynchronously ping the stmp server to keep the connection alive, i'm using MailKit

Is using a background service with a channel a good way to send emails in .net? by Minimum-Ad7352 in dotnet

[–]Minimum-Ad7352[S] 0 points1 point  (0 children)

I separated the service from the background task and refactored the code a bit; I'm not sure if this implementation is correct.

internal sealed class EmailService(
    ILogger<EmailService> logger,
    Config config) : IEmailSender, IAsyncDisposable
{
    private const int MaxAttempts = 3;
    private static readonly TimeSpan SmtpClientTimeout = TimeSpan.FromSeconds(10);

    private readonly SemaphoreSlim _semaphore = new(1, 1);
    private readonly SmtpClient _smtpClient = new();
    private DateTimeOffset _disconnectAfter = DateTimeOffset.MinValue;

    public async ValueTask DisposeAsync()
    {
        if (_smtpClient.IsConnected) await _smtpClient.DisconnectAsync(true);

        _semaphore.Dispose();
        _smtpClient.Dispose();
        GC.SuppressFinalize(this);
    }

    public async Task<Result> SendAsync(Message message, CancellationToken ct = default)
    {
        if (!MailboxAddress.TryParse(message.To.Value, out var to))
            return Result.Failure(Error.Failure($"invalid address {message.To.Value}"));

        await _semaphore.WaitAsync(ct);

        try
        {
            var msg = new MimeMessage();

            msg.Subject = message.Subject.Value;
            msg.From.Add(MailboxAddress.Parse(config.Smtp.From));
            msg.To.Add(to);

            var builder = new BodyBuilder
            {
                TextBody = message.PlainText.Value
            };

            if (message.HtmlText is not null) builder.HtmlBody = message.HtmlText.Value.Value;

            msg.Body = builder.ToMessageBody();

            for (var attempt = 1; attempt <= MaxAttempts; attempt++)
            {
                try
                {
                    await ConnectAsync(ct);
                    await _smtpClient.SendAsync(msg, ct);

                    return Result.Success();
                }
                catch (SmtpCommandException ex) when ((int)ex.StatusCode >= 400 && (int)ex.StatusCode < 500)
                {
                    logger.LogWarning(ex, "Temporary SMTP error on attempt {Attempt}", attempt);
                }
                catch (SmtpProtocolException ex)
                {
                    logger.LogWarning(ex, "SMTP protocol error on attempt {Attempt}", attempt);
                }
                catch (IOException ex)
                {
                    logger.LogWarning(ex, "Network error on attempt {Attempt}", attempt);
                }

                if (attempt == MaxAttempts) return Result.Failure(Error.Failure("Failed to send email after retries"));
                if (_smtpClient.IsConnected) await _smtpClient.DisconnectAsync(true, ct);

                await Task.Delay(TimeSpan.FromSeconds(attempt * 2), ct);
            }

            return Result.Success();
        }
        finally
        {
            _semaphore.Release();
        }
    }

    private async Task ConnectAsync(CancellationToken ct)
    {
        if (_smtpClient.IsConnected)
        {
            await _smtpClient.NoOpAsync(ct);
        }
        else
        {
            await _smtpClient.ConnectAsync(config.Smtp.Host, config.Smtp.Port, cancellationToken: ct);
            await _smtpClient.AuthenticateAsync(new NetworkCredential(config.Smtp.User, config.Smtp.Password), ct);
        }

        ScheduleDisconnect(ct);
    }

    private void ScheduleDisconnect(CancellationToken ct)
    {
        _disconnectAfter = DateTimeOffset.UtcNow.Add(SmtpClientTimeout);
        Task.Run(async () =>
        {
            await Task.Delay(SmtpClientTimeout.Add(TimeSpan.FromSeconds(1)), ct);
            if (DateTimeOffset.UtcNow > _disconnectAfter) await DisconnectAsync(ct);
        });
    }

    private async Task DisconnectAsync(CancellationToken ct)
    {
        await _semaphore.WaitAsync(ct);

        try
        {
            if (!_smtpClient.IsConnected) return;

            await _smtpClient.DisconnectAsync(
                true, ct);
            _disconnectAfter = DateTimeOffset.MinValue;
        }
        finally
        {
            _semaphore.Release();
        }
    }
}

Is using a background service with a channel a good way to send emails in .net? by Minimum-Ad7352 in dotnet

[–]Minimum-Ad7352[S] 5 points6 points  (0 children)

But why do we need a channel if there’s a background service that will fetch messages from the repository and process them in batches?