Hangfire 依赖注入生命周期范围 [英] Hangfire dependency injection lifetime scope

查看:32
本文介绍了Hangfire 依赖注入生命周期范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在重写整个问题,因为我知道原因,但仍然需要一个解决方案:

I'm rewriting this entire question because I realize the cause, but still need a solution:

我在 Hangfire 中有一项重复性工作,它每分钟运行一次并检查数据库,可能会更新一些内容,然后退出.

I have a recurring job in Hangfire that runs every minute and check the database, possibly updates some stuff, then exits.

我将我的 dbcontext 注入到包含作业方法的类中.我注册此 dbcontext 以使用以下内容进行注入

I inject my dbcontext into the class containing the job method. I register this dbcontext to get injected using the following

builder.RegisterType<ApplicationDbContext>().As<ApplicationDbContext>().InstancePerLifetimeScope();

然而,Hangfire 似乎并没有在每次作业运行时创建一个单独的生命周期范围,因为构造函数只被调用一次,尽管作业方法 get 每分钟被调用一次.

However, it seems that Hangfire does not create a seperate lifetime scope every time the job runs, because the constructor only gets called once, although the job method get's called every minute.

这给我带来了问题.如果用户更新了数据库中的某些值(dbcontext 被注入到其他地方,并用于更新值),则仍在使用的上下文 Hangfire 开始返回已更改的过时值.

This causes issues for me. If the user updates some values in the database (dbcontext gets injected somewhere else, and used to update values), the context still being used Hangfire starts returning out-dated values that have already been changed.

推荐答案

Hangfire 目前为每个 Worker 使用一个共享的 JobActivator 实例,它们使用以下方法来解决依赖项:

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)

计划为 Milestone 2.0.0 添加 JobActivationContext 到此方法.

It is planned to add a JobActivationContext to this method for Milestone 2.0.0.

目前,无法确定依赖项针对哪个作业得到解决.我能想到的解决此问题的唯一方法是利用作业在不同线程上串行运行的事实(我不知道 AutoFac,所以我以 Unity 为例).

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).

您可以创建一个 JobActivator 来为每个线程存储单独的作用域:

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;
    }
}

使用带有 IServerFilter 实现的 JobFilter 来为每个作业(线程)设置此范围:

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();
    }
}

最后设置您的 DI:

UnityJobActivator unityJobActivator = new UnityJobActivator(new UnityContainer());
JobActivator.Current = unityJobActivator;

GlobalJobFilters.Filters.Add(new ChildContainerPerJobFilterAttribute(unityJobActivator));

这篇关于Hangfire 依赖注入生命周期范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆