3
votes

I'm using EF Core and Hangfire to run a recurring job. Hangfire seems to be causing the following error:

A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext

And.. I'm not sure why. I register the EF context as follows:

services 
    .AddDbContext<PaymentContext>(options => options.UseNpgsql(connectionString),
    ServiceLifetime.Transient); 

And then..

app.UseHangfireDashboard();
app.UseHangfireServer();
   
RecurringJob.AddOrUpdate(() => myService.ExecuteMyJob(), Cron.Minutely);

Where myService has been injected into the Startup.Configure function, and myService contains the reference to the DbContext. Which is transient in theory, and so shouldn't be shared by the service and other places.

However the stacktrace leads here:

var plans = _context.Plan
                .Include(pp => pp.PlanItem)
                .Where(pp => pp.PolicyId == policyId)
                .ToList() // materialise query
                .OrderBy(pp => pp.PlanItem.First().Date)
                .ToList();
1
Welcome to Stack Overflow. Please edit your question to include the source code you have as a minimal reproducible example, which can be compiled and tested by others. - Progman
What are the details of your ExecuteMyJob()? (void, Task, async) - Nick Albrecht
All your Hangfire jobs must create a new Dependency Scope, done with IServiceProvider.CreateScope. - Frank Nielsen

1 Answers

1
votes

You should create scope for your dependency.

public class Job
{
    private readonly IServiceProvider _serviceProvider;
    
    public Job(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public void ExecuteJob()
    {
        using (var scope = serviceProvider.CreateScope())
        {
            var databaseContext = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
            // do something
        }
    }
}