Open aleksvujic opened 1 year ago
We are experiencing the same issue since recently.
After looking into the codebase we have a guess that it is related to this line of code:
What is happening:
There were cases like this before: https://github.com/HangfireIO/Hangfire/issues/1099 I don't think it was actually fixed.
For the original question, this exception is thrown likely because ASP.NET Core host is shutting down. And in this case we should understand why this happens, and especially why we are executing business logic after application is shutting down, because in this case it is expected that nothing will be called.
Regarding unit tests, Hangfire for historical reasons uses static fields for its configuration and perhaps the best way is to avoid running such tests in parallel.
Something like this is happening:
As a workaround, I had to disable the hangfire Hosted service from starting in the tests.
Potential solution: Since LibLog is discontinued, maybe it is time to take the dependency on Microsoft.Extensions.Logging
With serial tests you'll be able to call LogProvider.SetCurrentLogProvider
before each test runs, so that each test will have a fresh logging provider instance. If you are using non-static BackgroundJobClient
or RecurringJobManager
classes instead of static Background/RecurringJob
that you'll have no static logger references.
Or alternatively you can just use NoOpLogProvider
to avoid using logger from .NET Core that throws exceptions after being disposed.
There are no problems with LibLog, exception is arising from Microsoft's log provider that was disposed.
There are no problems with LibLog, exception is arising from Microsoft's log provider that was disposed.
It is not a problem, it is a design limitation of the LibLog. It sets a static variable. The tests are in the common process space. Hence, overlapping.
Microsoft's log provider that was disposed.
That is correct. I asked it to. That is what is happening when the test case is over. But the reference(the wrong one by the way) to the log provider got stuck in the static field.
Static configuration unfortunately is the problem for Hangfire itself, not only for LibLog.
Any plans to replace the LibLog with the Microsoft.Extensions.Logging?
Having the same issue. I also disabled Hangfire from running in Integration tests for now...
Since we are using .NET 6 and NUnit with WebApplicationFactory for integration tests I've overridden implementation of Hangfire interface that does nothing.
Posting since maybe it will be useful for someone.
public class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(OverrideExistingHangfireInterfaceImplementation);
}
private static void OverrideExistingHangfireInterfaceImplementation(IServiceCollection services)
{
// Find the existing registration and remove it
var descriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(IHangfireRecurringJobManager));
if (descriptor != null)
{
services.Remove(descriptor);
}
// Add a new registration
services.AddTransient<IHangfireRecurringJobManager, StubHangfireRecurringJobManager>();
}
}
public class StubHangfireRecurringJobManager : IHangfireRecurringJobManager
{
public void AddOrUpdate(string recurringJobId, Expression<Action> methodCall, string cronExpression)
{
}
public void AddOrUpdate(string recurringJobId, Expression<Func<Task>> methodCall, string cronExpression)
{
}
public void RemoveIfExists(string recurringJobId)
{
}
}
I was experiencing an issue with using AutomaticRetryAttribute
in my unit tests that produced the same issue as described by OP. I found that in my case, I could provide an alternative implementation to the built in one, as a workaround:
internal class NoRetryAttribute : JobFilterAttribute, IElectStateFilter
{
public void OnStateElection(ElectStateContext context)
{
// No-op overrides the default retry behaviour.
}
}
I then use it in my unit test setup like:
// For testing purposes, we will not perform any retries.
GlobalConfiguration.Configuration.UseFilter(new NoRetryAttribute());
Note: I'm using AspNetCore, .Net 8.0 and implementing Integration tests along the lines of the MS recommendations.
We are using .NET 6, Hangfire.AspNetCore 1.7.31 and Hangfire.InMemory 0.3.4. This is how we configure Hangfire in
Startup.cs
:We have a unit test which calls
RecurringJob.RemoveIfExists("jobId")
somewhere in its body. This test was working for a long time and failed randomly today. We re-ran the test multiple times but we were unable to reproduce the exception.Error message:
Stacktrace:
Why did the exception occur? How can we prevent it from happening again?