繁体   English   中英

一次仅允许一个用户访问操作

[英]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在给定时间(但不超过阈值时间)并返回,则他/她可以舒适地继续操作
  • 最近15分钟未处理该对象。 这实际上是我在前面提到的阈值。 至于多长时间(在我的示例中为15分钟),这实际上取决于您。

如果为用户返回了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.

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