Hangfire currently uses a shared Instance of JobActivator
for every Worker, which are using the following method for resolving a dependency:
public override object ActivateJob(Type jobType)
It is planned to add a JobActivationContext to this method for Milestone 2.0.0.
For now, there is no way to say for which job a dependency gets resolved. The only way I can think of to workaround this issue would be to use the fact that jobs are running serial on different threads (I don't know AutoFac so I use Unity as an example).
You could create a JobActivator
that can store separate scopes per thread:
public class UnityJobActivator : JobActivator
{
[ThreadStatic]
private static IUnityContainer childContainer;
public UnityJobActivator(IUnityContainer container)
{
// Register dependencies
container.RegisterType<MyService>(new HierarchicalLifetimeManager());
Container = container;
}
public IUnityContainer Container { get; set; }
public override object ActivateJob(Type jobType)
{
return childContainer.Resolve(jobType);
}
public void CreateChildContainer()
{
childContainer = Container.CreateChildContainer();
}
public void DisposeChildContainer()
{
childContainer.Dispose();
childContainer = null;
}
}
Use a JobFilter
with IServerFilter
implementation to set this scope for every job (thread):
public class ChildContainerPerJobFilterAttribute : JobFilterAttribute, IServerFilter
{
public ChildContainerPerJobFilterAttribute(UnityJobActivator unityJobActivator)
{
UnityJobActivator = unityJobActivator;
}
public UnityJobActivator UnityJobActivator { get; set; }
public void OnPerformed(PerformedContext filterContext)
{
UnityJobActivator.DisposeChildContainer();
}
public void OnPerforming(PerformingContext filterContext)
{
UnityJobActivator.CreateChildContainer();
}
}
And finally setup your DI:
UnityJobActivator unityJobActivator = new UnityJobActivator(new UnityContainer());
JobActivator.Current = unityJobActivator;
GlobalJobFilters.Filters.Add(new ChildContainerPerJobFilterAttribute(unityJobActivator));
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…