繁体   English   中英

Hangfire - DisableConcurrentExecution - 如果在方法参数中传递相同的值,则阻止并发执行

[英]Hangfire - DisableConcurrentExecution - Prevent concurrent execution if same value passed in method parameter

Hangfire DisableConcurrentExecution属性未按预期工作。

我有一种方法,可以用不同的 ID 调用。 如果传递了相同的 ID,我想阻止方法的并发执行。

string jobName= $"{Id} - Entry Job";

_recurringJobManager.AddOrUpdate<EntryJob>(jobName, j => j.RunAsync(Id, Null), "0 2 * * *");

我的 EntryJob 接口具有 RunAsync 方法。

public class EntryJob:  IJob
  {
 [DisableConcurrentExecution(3600)] <-- Tried here
public async Task RunAsync(int Id, SomeObj obj)
    {
      //Some coe
    }
  }

界面看起来像这样

 [DisableConcurrentExecution(3600)] <-- Tried here
    public interface IJob
      {
       [DisableConcurrentExecution(3600)] <-- Tried here
        Task RunAsync(int Id, SomeObj obj);
      }

现在,如果 Id 相同,我想阻止 RunAsync 方法多次调用。 我试图将DisableConcurrentExecution放在 RunAsync 方法的顶部,位于接口声明内的位置以及实现接口的位置。

但似乎对我不起作用。 有没有办法防止基于Id的并发?

DisableConcurrentExecution 的现有实现不支持这一点。 它将阻止使用任何参数同时执行该方法。 添加支持将相当简单。 下面的注释是未经测试的伪代码:

public class DisableConcurrentExecutionWithArgAttribute : JobFilterAttribute, IServerFilter
{
    private readonly int _timeoutInSeconds;
    private readonly int _argPos;

    // add additional param to pass in which method arg you want to use for 
    // deduping jobs
    public DisableConcurrentExecutionAttribute(int timeoutInSeconds, int argPos)
    {
        if (timeoutInSeconds < 0) throw new ArgumentException("Timeout argument value should be greater that zero.");

        _timeoutInSeconds = timeoutInSeconds;
        _argPos = argPos;
    }

    public void OnPerforming(PerformingContext filterContext)
    {
        var resource = GetResource(filterContext.BackgroundJob.Job);

        var timeout = TimeSpan.FromSeconds(_timeoutInSeconds);

        var distributedLock = filterContext.Connection.AcquireDistributedLock(resource, timeout);
        filterContext.Items["DistributedLock"] = distributedLock;
    }

    public void OnPerformed(PerformedContext filterContext)
    {
        if (!filterContext.Items.ContainsKey("DistributedLock"))
        {
            throw new InvalidOperationException("Can not release a distributed lock: it was not acquired.");
        }

        var distributedLock = (IDisposable)filterContext.Items["DistributedLock"];
        distributedLock.Dispose();
    }

    private static string GetResource(Job job)
    {
        // adjust locked resource to include the argument to make it unique
        // for a given ID
        return $"{job.Type.ToGenericTypeString()}.{job.Method.Name}.{job.Args[_argPos].ToString()}";
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM