繁体   English   中英

并发请求预防

[英]Concurrent requests prevention

我想使我的API的某些方法被锁定( HttpStatus.Conflict ),直到另一个具有相同参数的方法没有完成(例如?id = 1&key = sd6gd0f1g5ds16fh),就像坏用户试图一次发出2个以上相同的请求一样,一个会完成。 我的想法是使用Semaphore

public class Lock : IDisposable
{
    private bool _disposed = false;

    private readonly Semaphore _semaphore;

    public bool IsLocked
    {
        get;
        private set;
    }

    public Lock(string name)
    {
        this.IsLocked = false;
        try
        {
            this._semaphore = Semaphore.OpenExisting(name);
            this._semaphore.Close();
        }
        catch (Exception)
        {
            this._semaphore = new Semaphore(0, 1, name);
            this.IsLocked = true;
        }
    }

    ~Lock()
    {
        this.Dispose(false);
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!this._disposed)
        {
            if (disposing)
            {
                this._semaphore.Release();
                this._semaphore.Dispose();
            }

            this._disposed = true;
        }
    }
}

我正在这样使用它:

[ActionName("Ping")]
[HttpGet]
public IHttpActionResult Ping([FromUri]int? id = null, [FromUri]string key = null)
{
    if (id == null)
    {
        //ProcessException is some wrap for api error answer
        throw new ProcessException(HttpStatusCode.BadRequest, "Service ID is required");
    }

    if (key == null)
    {
        throw new ProcessException(HttpStatusCode.BadRequest, "Service Key is required");
    }

    Lock serviceLock = new Lock("service." + id + "." + key);
    if (!serviceLock.IsLocked)
    {
        throw new ProcessException(HttpStatusCode.Conflict, "Other Service operation already in progress");
    }

    var service = Service.Get((int)id, key);
    if (service == null) // Right hereino
    {
        throw new ProcessException(HttpStatusCode.Forbidden, "Service ID and/or Key is invalid");
    }

    Service.Touch((int)id);

    serviceLock.Dispose();

    //JResponse is some wrap for Dictionary<string, object>
    return Ok(new JResponse(true));
}

但是我对此很陌生,并且有一些问题:

  1. 我朝着正确的方向前进吗?
  2. 当我调用Dispose ,下一个请求仍会存在Semaphore 怎么了?
  3. 我的课程会在某些例外情况下被处置(并释放Semaphore )吗? (就像上面我们看到的,如果service == null

这不是完美的,还有改进的余地,但认为这可能会使您从另一个方向或另一种思维方式开始。

使用您的信号量东西来锁定静态字典

//ToDo: You would have to make this ThreadSafe
public static class Helper
{
    public static Dictionary<string,ClientDto> ClientDtos 
    = new Dictionary<string, ClientDto>();
}

public class ClientDto
{
    public int ClientKey { get; set; }
    public string Key { get; set; }
    public DateTime CreatedOn { get; set; }
}

in your Global.asax add.
protected void Application_EndRequest()
{
    Helper.ClientDtos.Remove(SeesionId);
}

//if this is called twice by the same client and the request is 
//not finished processing the first request the second one will go into    
//RequestBeingHandled and just return preventing the code from preforming 
//the same action until the first/current is complete.

public IHttpActionResult Ping([FromUri]int? id = null, [FromUri]string key = null)
{
    if(RequestBeingHandled(id, key))
    {
        //
        Return .....
    }
    else 
    {
        //if not add 
        ClientDto client = new ClientDto();
        client.ClientKey = id;
        client.Key = key;
        client.CreatedOn = DateTime.Now;
        Helper.ClientDtos.Add(SeesionId, client);
    }
    //call some code to do stuff...
}

private bool RequestBeingHandled(int id, string key)
{
    //ToDo: write this code.
    //check if its already in the dic
    return bool;
}

暂无
暂无

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

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