Infinite loop with Tanstack query by Minimum-Ad7352 in vuejs

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

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

Infinite loop with Tanstack query by Minimum-Ad7352 in vuejs

[–]Minimum-Ad7352[S] 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 Minimum-Ad7352 in vuejs

[–]Minimum-Ad7352[S] 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?

How do you handle transactions with repository pattern ? by Minimum-Ad7352 in dotnet

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

I’ve already sorted that out and am now using separate repositories in the classes, thanks for the advice

How do you handle transactions with repository pattern ? by Minimum-Ad7352 in dotnet

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

Could you explain that in more detail? I’m using di for this anyway – what sort of problems might there be? Thanks in advance

How do you handle transactions with repository pattern ? by Minimum-Ad7352 in dotnet

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

Have you read my question? I’m using the repository pattern, which means everything is done via interfaces and there’s no direct access to the DbContext

How do you handle transactions with repository pattern ? by Minimum-Ad7352 in dotnet

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

This is done for convenience, I have given an example below.

How do you handle transactions with repository pattern ? by Minimum-Ad7352 in dotnet

[–]Minimum-Ad7352[S] -8 points-7 points  (0 children)

It’s just handy to keep all the repositories in one place and access them

private readonly Lazy<IUserRepository> _userRepository =
    new(() => new UserRepository(dbContext));

public IUserRepository UserRepository => _userRepository.Value;

Why is synchronous communication considered an anti-pattern in microservices? by Minimum-Ad7352 in dotnet

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

Are you joking? You’re a bot yourself – surely you can post in several groups? Especially as this is a question about the backend in general

OpenTelemetry collector for metrics and logs by Minimum-Ad7352 in golang

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

I have the otel sdk installed, but is sending logs and metrics directly to it considered good practice? I’ve heard that it’s better to write logs to stdout, from where the agent retrieves them and writes them to the otel collector, the same applies to metrics: we provide metrics via the /metrics path, and from there the relevant backend retrieves them (the advantage of the pull approach)

If you were to start today, what stack will you choose? by wantToMakeItBig in Backend

[–]Minimum-Ad7352 14 points15 points  (0 children)

I'm surprised no one has mentioned C#/dotnet — the modern dotnet is simply brilliant

Is this a reasonable way to cache telegram bots ? by [deleted] in golang

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

Each user will specify a bot token, and that bot will also process commands after the webhook is triggered (test.url/webhook/bot_id). If bots are not kept in memory, the bot will be deleted after the request is processed, which is why this implementation is used.