[英]Allow access to operation only one user at the time
我有与Web API通信的ASP.NET Core应用程序。 有一个涉及几个步骤的业务操作(在一页上执行,转到下一页和下一页)。 此多步骤操作是在一个元素的上下文中完成的。
因此,假设您有一些业务对象的列表,而您的任务是从该列表中接受对象3 。 接受是我们的多步骤操作,如果我当前正在接受对象3,则任何人都不能输入对象3的接受操作。 完成操作后,应将其解锁。 希望这个问题是可以理解的。
我们不需要非常耗时的解决方案,最简单的想法是创建一个数据库表来指示用户何时开始操作,它保存对象的ID和用户的ID,例如在5分钟后自动删除自身(如果有人)否则要访问操作,我们检查该对象是否被阻止。 但这有点骇人听闻,而且不是很干净(如果用户去喝咖啡并在10分钟后继续操作该怎么办?)
我正在寻找一种更好的方式来实现这种行为并欣赏任何想法
如果要实现该行为,我还将使用数据库,但使用另一种方式。 我将创建一个对象表( 对象3是其行之一),为UserId
添加一列,为布尔值OnProcess
(以标记对象是否在进程中)和StartProcess
时间戳添加一列。
为了使用户能够输入操作,请运行以下查询:
UPDATE Objects SET UserId = <CurrentUser>, StartProcess = <NOW>, OnProcess = true
OUTPUT Object.Id
WHERE Object.Id == 3 AND
(
OnProcess == false
OR ( OnProcess == true AND UserId == <CurrentUser> )
OR ( StartProcess <is more than 15 minutes ago>)
)
免责声明:上面的查询不是可执行查询,但是应该足够清楚地了解它的作用。
通过上面的查询,在以下情况下将返回Object.Id
:
CurrentUser
本身处理,也重置了StartProcess
(某种滑动行为)。 这样,如果CurrentUser
AFK在给定时间(但不超过阈值时间)并返回,则他/她可以舒适地继续操作 如果为用户返回了Object.Id
,则他/她能够输入操作。
您正在寻找信号量。 lock
关键字是最基本的信号量,但是您也可以使用Semaphore
/ SemaphoreSlim
,它们提供了执行速率限制之类的功能,而lock
实际上每次将选通一个操作。 但是,您的目标是针对特定资源一次选择一个操作,这使SemaphoreSlim
成为更好的选择,特别是ConcurrentDictionary<string, SemaphoreSlim>
。
您将需要一个具有单例生存期的类(在应用程序的整个生命周期中一个实例)。 在那里,您将添加一个ivar:
private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphores = new ConcurrentDictionary<string, SemaphoreSlim>();
然后,您将在要进行门操作的周围添加以下代码:
var semaphore = _semaphores.GetOrAdd("object3", _ => new SemaphoreSlim(1, 1));
await semaphore.WaitAsync();
// do something
semaphore.Release();
"object3"
显然只有一个占位符。 您将想要使用任何有意义的东西(ID等)-可以唯一地标识您要控制的特定资源的东西。 然后,仅当该特定资源上存在现有操作时,该操作才会保存该特定资源的操作。 不同的资源将获得其自己的信号量,并因此获得其自己的门。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.