我有几个微服务(用 ruby 实现,尽管我怀疑这对我的问题是否重要)。其中一个提供项目,另一个处理它们,然后将它们标记为已处理(通过 DELETE 调用)
提供者有一个 /items
端点,它以 JSON 格式列出了一堆用 id 标识的项目。它还有一个 DELETE/items/id
端点,它从列表中删除一个项目(大概是因为它已被处理)
“处理器”中的代码(非常简化)如下所示:
items = <GET provider/items>
items.each do |item|
process item
<DELETE provider/items/#{item.id}>
end
这有几个问题,但我想解决的一个问题是它不是线程安全的,因此我不能并行运行它。如果两个工作人员同时开始处理项目,他们将“踩到对方的脚趾”:他们将获得相同的项目列表,然后(尝试)处理和删除每个项目两次。
更改此设置以允许并行处理的最简单方法是什么?
您可以假设我有 ruby 可用。我宁愿将更改保持在最低限度,并且如果可能的话宁愿不安装其他 gem。 Sidekiq可作为消费者上的排队系统使用。
最佳答案
一些备选方案(只是集思广益):
- 只需放弃 HTTP 并使用带有队列的发布-订阅。让生产者排队,一些消费者处理它们(并触发状态变化,如果你喜欢的话,在这种情况下使用 HTTP)。
如果您真的想要 HTTP,我认为还有一些遗漏的地方。如果您的项目的状态是pending 和processed,则您的状态机中存在隐藏/隐式状态:in_progress(或其他)。一旦您想到它,情况就会变得更加清晰:您的
GET/items
不是幂等的(因为它将项目的状态从待处理更改为进行中),因此首先不应该是 GET。一个。另一种方法是添加一个新实体(例如批处理),该实体通过 POST 创建并将一些项目分组并发送。已经退回的项目不会成为 future 批处理的一部分,然后您可以将整个批处理标记为已完成(例如
PUT/batches/X/done
)。这很快就会变得疯狂,因为您将开始重新实现队列系统和普通/显式(参见 c)HTTP 中已经存在的特性(确认、超时、错误)。一个稍微简单的替代方案:只需在
POST
/PUT
(两种情况下都很奇怪)端点中将/items
标记为正在处理的项目(和不再返回它们,因为它只返回待处理的项目)。但是,错误和超时也存在同样的问题。让生产者明确并通过 PUT 向其他服务请求处理项目。您可以在正文中包含所有需要的数据,或者将其用作 ping 并让处理器通过 GET 请求信息。您可以在任一侧添加异步处理(但在处理器中可能更好)。
我会诚实地做 1(除非有令人信服的理由)。
关于ruby-on-rails - 如何更改这些生产者-消费者微服务以允许并行处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27839789/