0
\$\begingroup\$

In an application there is a table for one-time-passwords (OTP) which will be sent to users via SMS. These OTPs are needed for a maximum of two hours in order to detect abusing behaviours.

A simple DB cleaner will delete these rows (DeleteAsync is from this library):

public class DbCleaner : BackgroundService
{
    private readonly IServiceProvider serviceProvider;
    private readonly ILogService logService;

    public DbCleaner(
        IServiceProvider serviceProvider,
        ILogService logService)
    {
        this.serviceProvider = serviceProvider;
        this.logService = logService;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            using var scope = serviceProvider.CreateScope();
            var dbContext = scope.ServiceProvider.GetRequiredService<IdentityDbContext>();

            var otpDeleted = await dbContext.OTP
                .IgnoreQueryFilters()
                .Where(x => x.CreationTime.AddHours(2) >= DateTimeOffset.UtcNow)
                .DeleteAsync();

            await LogOperationAsync(otpDeleted);

            try
            {
                await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
            }
            catch (TaskCanceledException)
            {
                // application is shutting down
                // ignore this
            }
        }
    }

    private Task LogOperationAsync(int otpCount)
    {
        // ...
    }
}

On every publish, the timer will be reset which is fine for this project.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Why don't you use a database job for this? \$\endgroup\$ Jul 16, 2022 at 9:45
  • \$\begingroup\$ Everything is code first \$\endgroup\$
    – Parsa99
    Jul 16, 2022 at 10:38
  • 1
    \$\begingroup\$ @Parsa99 you could implement the proper procedures to create and modify the sql jobs from code first approach, and reuse them from you code. \$\endgroup\$
    – iSR5
    Jul 16, 2022 at 10:58
  • \$\begingroup\$ Can you please share a resource? I am using EF Core 6 with Npgsql (PostgreSQL 14). \$\endgroup\$
    – Parsa99
    Jul 16, 2022 at 12:34
  • \$\begingroup\$ @Parsa99 npsql is a bit different, however, you could read about available job scheduler and see how you can reuse it as store procedure from your code. severalnines.com/blog/overview-job-scheduling-tools-postgresql \$\endgroup\$
    – iSR5
    Jul 16, 2022 at 13:21

1 Answer 1

1
\$\begingroup\$

This appears to be the opposite of what you want:

.Where(x => x.CreationTime.AddHours(2) >= DateTimeOffset.UtcNow)

This would be a lot easier to read with a named variable like:

var deleteBefore = DateTime.Now.AddHours(-2);
.Where(x => x.CreationTime < deleteBefore)

It would also be good to have the 2 hours pulled out into a named constant at class level. Another thing to consider is having the expiration time explicitly stored as a column, instead of having the code compute it from the creation time.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.