API使用.NET内核调用“FIFO”

rsl1atfo  于 2023-01-27  发布在  .NET
关注(0)|答案(2)|浏览(123)

我有一个API端点,通过身份验证的用户可以使用它来预订活动。一旦对API的预订调用成功,该数量的位置就会被“消耗”,无法由其他用户预订。
我试图实现的是组织并发调用,以***避免***出现以下情况:

  • 会场有10个名额
  • 用户A进行API调用以预留6个位置
  • 用户B在大约相同的时间(毫秒之后)进行API调用以预留5个位置
  • 在来自用户A的呼叫完成并锁定6个位置之前,来自用户B的呼叫继续进行,好像它将成功一样,因为它看到10个位置可用。

基本上,我是在尝试按顺序组织我的电话。
关于进一步考虑:

  • 我正在使用Microsoft Azure -我是否应该考虑使用排序队列?
  • 我还使用EF核心为我的后端数据,如果这可以使不同的方式,我不能想到。
  • 有没有一个库可以用来实现这种类似信号量的方法?

我完全理解,在作为一个替代方案,我可以软保留一个点,在一个时间为每个用户,只有当所有的点得到软保留成功,我然后继续和硬保留他们.在我走一些路线像这样一个,我很好奇,如果有一些不那么笨拙的方法.
谢谢

y0u0uwnf

y0u0uwnf1#

    • 同步**

如果你同意在数据库级别使用悲观锁,你可以不用队列或异步来解决这个问题。悲观锁本质上是一种序列化的方法。我不推荐使用进程内锁,比如lock关键字/互斥锁等等。现代的API有多个示例,所以排除了单机/内存互斥锁。
您可以立即(同步)调用某种类型的持久存储(例如,专用于预留插槽的表)来预留M插槽。这可能类似于"update the record where NAvailable - M >= 0"。"该记录"将通过一些标准(例如房间ID)来标识。

  • 如果该事务成功了,那么它成功了 * 而该记录被锁定以进行更新 *,这意味着其他调用将被阻塞,直到您从该事务返回为止。然后,这些调用将能够继续其尝试。这是安全的,所以您可以从API POST返回201 CREATED(它是POST,因为您要求创建一个保留)。
  • 如果该事务失败,这仅仅意味着没有足够的槽来执行该调用,您可以返回一个409 CONFLICT,这意味着客户端的请求是合法的,但是由于系统的状态(没有足够的槽)而不能被满足。
    • 异步**

这必然会更加复杂,但可能会增加解决方案的并发性。在这种情况下,您通常会接受来自客户端的所有调用,并将它们排入队列。同样,您可以使用ConcurrentQueue等内存中解决方案来序列化请求,但最好使用使用Azure队列等"真正"排队机制的分布式解决方案。
在这个场景中,每个客户端请求都会立即被放到队列中,API返回一个202 ACCEPTED,队列的使用者尝试完成请求,整个工作流将遵循Asynchronous Request-Reply pattern
这需要在服务器(跟踪工作和实现)和客户机(轮询以确定工作是否真正成功,或者响应SignalR的推送通知)上进行更多的工作。

    • 总结**

我正在使用Microsoft Azure-我是否应该考虑使用排序队列?
是的。这是合理的,而且从并发的Angular 来看更为乐观。使用"软保留"扩展了这种方法,不仅合理,而且很常见;考虑在飞机上预订座位。您可以在很短的时间内获得座位,但不会永远获得。工作流更加复杂,但如果乐观并发失败,则允许使用compensating transactions
我还使用EF核心为我的后端数据,如果这可以使不同的方式,我不能想到。
我不认为这会有什么不同。这是对数据库的抽象。
有没有一个库可以用来实现这种类似信号量的方法?
也许吧,大多数都属于模式领域,这意味着您可能可以使用一些样板代码(我知道我已经这样做过几次了!)或一个编码模式的框架。

gcuhipw9

gcuhipw92#

这是多线程系统中的一个常见问题。有很多方法可以解决这个问题,但如果调用速度快,负载不是很大,你可能可以用ReaderWriterLockSlim这样的东西来解决。我不太精通Azure,但如果我自己编写服务器,这将是我快速而肮脏的解决方案。

相关问题