.net 如何防止多个控制器动作的并发执行?

wi3ka0sx  于 2023-11-20  发布在  .NET
关注(0)|答案(2)|浏览(163)

该方法查询和聚合来自第三方API的结果,如果发出太多请求,该API可能会失控。
我考虑的方法是在Autofac中将控制器注册为单例,并使用锁来管理字段级变量的状态,该变量跟踪方法是否已经在进行中。
这是一个干净的实现还是它包含bug/竞争条件?

public class  ExpensiveController : Controller
{
    private bool _alreadyRunning = false;
    private static readonly object Instancelock = new object();

    [HttpGet("expensiveController/CallThirdPartyApi")]
    public ActionResult<IEnumerable<MyObject>>  CallThirdPartyApi()
    {
        // Critical Section Start
        lock (Instancelock)
        { 
            if (_alreadyRunning == true)
            {
                return Ok
            }
            else
            {
                _alreadyRunning = true;
            }
        } //Critical Section End
              
        // do work
        var list = DoExpensiveProcessing()
        _alreadyRunning = false;

        return list;
    }
}

字符串
下面是代码的清理版本,它使用一个静态字段来跟踪状态,而不是扰乱控制器的生命周期。

public class ExpensiveController : Controller
    {
        private static bool _alreadyRunning;
        private static readonly object InstanceLock = new object();

        [HttpGet("expensiveController/CallThirdPartyApi")]
        public ActionResult<IEnumerable<MyObject>>  CallThirdPartyApi()
        {
            lock (InstanceLock)
            {
                
                if (_alreadyRunning)
                {
                    return new ServiceUnavailableResult();
                }
                _alreadyRunning = true;
            }
             

            var list = DoExpensiveProcessing()
                
            
            lock (InstanceLock)
            {
                
                _alreadyRunning = false;
            }
            return list;
            }  
       
    }
}

jslywgbw

jslywgbw1#

一个简单的版本可以是

[HttpGet("expensiveController/CallThirdPartyApi")]
public ActionResult<IEnumerable<MyObject>>  CallThirdPartyApi()
{
    lock
    {
        //your work
    }

字符串

3xiyfsfu

3xiyfsfu2#

我创建了一个库,可以帮助你实现你的目标。它叫做AsyncKeyedLock,可以通过NuGet获得。如果你使用DI注入一个AsyncKeyedLocker<string>单例,你就可以通过键锁定,其中键是控制器的名称。这样你就可以控制你想要对每个控制器进行多少并发调用。

相关问题