如何在WebApi操作中锁定长时间的异步调用?
我有这种情况下,我有一个WebApi和一个端点,当被触发时做了很多工作(大约2-5分钟)。这是一个带有副作用的POST端点,我想限制执行,以便如果发送2个请求到这个端点(不应该发生,但是比对不起更安全),其中一个请等待以避免竞争条件。如何在WebApi操作中锁定长时间的异步调用?
我第一次尝试使用一个简单的静态锁控制器内是这样的:
lock (_lockObj)
{
var results = await _service.LongRunningWithSideEffects();
return Ok(results);
}
这是因为lock
语句内await
的当然是不可能的。
我考虑的另一个解决方案是使用一个SemaphoreSlim
实现这样的:
await semaphore.WaitAsync();
try
{
var results = await _service.LongRunningWithSideEffects();
return Ok(results);
}
finally
{
semaphore.Release();
}
然而,根据MSDN:
的SemaphoreSlim类表示可用于重量轻,快速旗语等待时间在之间,等待时间预计会很短。
由于在这种情况下,等待时间甚至可能会达到5分钟,我应该如何使用并发控制?
EDIT(响应plog17):
我明白,通过此任务到服务可能是最佳的方式,但是,我不一定要排队在仍然运行在后台的东西请求完成后。 该请求涉及需要一些时间的其他请求和集成,但我仍然希望用户等待此请求完成并获得响应。 这个请求预计只能在特定时间每天由cron作业触发一次。但是,也有一个选择可以由开发人员手动触发它(主要是为了防止作业出现问题),并且我想确保如果开发人员(例如,开发人员)不会遇到并发问题偶然发送请求等。
如果在给定的时间只有一个请求可以被处理,那么为什么不实施一个队列呢?
有了这样的设计,在处理长时间运行的请求时不再需要锁定或等待。
流量可能是:
- 客户端POST/RessourcesToProcess,应该得到迅速202接受的
HttpController简单地排队进行任务(并返回202接受的)
其他服务(Windows服务?)出队接下来的任务进行
- 继续任务
- 更新资源状态
在这个过程中,客户端应该能够轻松获得以前的请求的状态:
- 如果任务不发现:404-NotFound。找不到id的资源123
- 如果任务处理:200-OK。 123正在处理中。
- 如果完成任务:200-确定。处理响应。
你的控制器可能看起来像:
public class TaskController
{
//constructor and private members
[HttpPost, Route("")]
public void QueueTask(RequestBody body)
{
messageQueue.Add(body);
}
[HttpGet, Route("taskId")]
public void QueueTask(string taskId)
{
YourThing thing = tasksRepository.Get(taskId);
if (thing == null)
{
return NotFound("thing does not exist");
}
if (thing.IsProcessing)
{
return Ok("thing is processing");
}
if (!thing.IsProcessing)
{
return Ok("thing is not processing yet");
}
//here we assume thing had been processed
return Ok(thing.ResponseContent);
}
}
这种设计意味着你不处理你的WebAPI内长时间运行的过程。事实上,它可能不是最好的设计选择。如果您仍然想这样做,你可能需要阅读:
因为评论字数不多的,我在编辑的形式回答,请检查更新的问题。 – valorl