【问题标题】:Hangfire per-job correlationId/stateHangfire 每个作业相关性 ID/状态
【发布时间】:2022-02-15 21:26:00
【问题描述】:

我在 ASP.NET Core 上运行 Hangfire。 对于我们的其他项目,我们在进行 API 调用时传递了 CorrelationId,以便能够链接调用者和被调用者。 我们在 ASP.NET Core 中为此使用 IHttpContextAccessor 的 TraceIdentifier。

不幸的是,ASP.NET Core 用于在瞬态 IHttpContextAccessor 中获取作用域 CorrelationId 的技巧似乎不适用于 Hangfire 作业执行。 使用 Scoped 状态关联对象不起作用,因为它必须是 Transient 才能与系统的其余部分(日志记录等)一起工作

我曾经能够使用 ServiceLocator 反模式并解决瞬态服务中的作用域状态对象。 在不再支持的最新 ASP.NET Core 中,由于抛出大量异常而引发异常,使系统速度过慢。

Hangfire 是否已经提供了可以为每次作业执行提供唯一 ID 的东西?

干杯。

【问题讨论】:

  • 这种方法可能是一种选择:stackoverflow.com/a/57396553/1236044 这将是一种将 TraceId 流向作业执行的方法
  • 谢谢。我可以使用自定义 JobActivator 正常工作。建议的解决方案仍然存在范围服务与临时服务的问题(JobId 将保存在范围服务中,但我需要将其传递给临时服务)。
  • 大多数情况下,我使用包装 AsyncLocal 范围对象的服务来解决这个问题,类似于 stackoverflow.com/a/69971515/1236044 但也许我不明白你的问题
  • 谢谢,这让我找到了正确的方向。我认为它不起作用,但这只是因为 ASP.NET 在错误的时间设置了相关性。

标签: asp.net-core hangfire


【解决方案1】:

感谢 jbl 的评论,我再次查看了我正在做的事情,并设法让它通过杂乱无章的工作。

我有瞬态持有者 (基本上就是重命名的 HttpContextAccessor 类):

public class StateHolder
{
    private static AsyncLocal<ContextHolder> _contextCurrent = new AsyncLocal<ContextHolder>();

    public string State {
        get {
            return _contextCurrent.Value?.Context;
        }
        set {
            var holder = _contextCurrent.Value;
            if (holder != null)
            {
                holder.Context = null;
            }

            if (value != null)
            {
                _contextCurrent.Value = new ContextHolder { Context = value };
            }
        }
    }

    private class ContextHolder
    {
        public string Context;
    }
}

然后在 Hangfire 中,我将其连接到激活

public class LoggingActivator : JobActivator
{
    private readonly IServiceScopeFactory _serviceScopeFactory;
    private readonly ContextAccessor _contextAccessor;

    public LoggingActivator([NotNull] IServiceScopeFactory serviceScopeFactory, ContextAccessor contextAccessor)
    {
        _serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
        _contextAccessor = contextAccessor;
    }

    public override JobActivatorScope BeginScope(JobActivatorContext context)
    {
        return new LoggingActivatorScope(_serviceScopeFactory.CreateScope(), _contextAccessor);
    }
}

public class LoggingActivatorScope : JobActivatorScope
{
    private readonly IServiceScope _serviceScope;
    private readonly ContextAccessor _contextAccessor;

    public LoggingActivatorScope(
        [NotNull] IServiceScope serviceScope,
        ContextAccessor contextAccessor)
    {
        _serviceScope = serviceScope ?? throw new ArgumentNullException(nameof(serviceScope));
        _contextAccessor = contextAccessor;
    }

    public override object Resolve(Type type)
    {
        _contextAccessor.Context = Guid.NewGuid().ToString();

        return ActivatorUtilities.GetServiceOrCreateInstance(_serviceScope.ServiceProvider, type);
    }

    public override void DisposeScope()
    {
        _serviceScope.Dispose();
    }
}

这似乎工作正常。

【讨论】:

    猜你喜欢
    • 2020-01-23
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多