【问题标题】:Race condition - multiple application instances using one database竞争条件 - 使用一个数据库的多个应用程序实例
【发布时间】:2016-06-25 21:43:40
【问题描述】:

我计划将我的 Rails 应用程序扩展到多个实例,但它们仍将使用相同的数据库。如果两个用户最终使用应用程序的两个不同实例,编辑同一个帐户,那么这肯定会在某个地方引起竞争条件 - 鉴于这是一个 Rails 应用程序,防止这种情况的最佳方法是什么?

我所知道的唯一与数据库相关的设置允许指定实际服务器 IP。如果一个程序可以成为中间人,它会以某种方式解决问题......否则应用程序实例将不得不以某种方式相互通信,对吗??

除非有办法使用 Postgres 中的设置来解决这个问题...

任何帮助将不胜感激!谢谢!

【问题讨论】:

标签: ruby-on-rails postgresql scaling race-condition horizontal-scaling


【解决方案1】:

我建议实施 optimistic locking 策略。 Rails 开箱即用地支持这一点。为此编写一个成熟的教程超出了stackoverflow答案的范围。请在线查找详细说明。

基础是: 对于要保护的每个模型,您需要在模型的数据库表中添加一个名为 lock_version 的整数列。另外,在每个表单中,您都需要添加一个带有此 lock_version 的隐藏字段。如果您使用的是安全参数,当然也可以在控制器中使用 lock_version 参数。

每当您保存记录并且存在 lock_version 时,Rails 都会确保 lock_version 与数据库中的匹配。如果它们不匹配,这意味着同时发生了另一个更新,并且当前更新失败并显示StaleObjectError

作为一种后备策略,我建议您向更新被拒绝的用户显示一条消息。此外,使用数据库中的当前值(不是尝试的输入,因为您希望用户重新考虑他们的更改是否合适)再次呈现他们正在填写的相同表单。

(您可以通过在您的ApplicationController 中定义一个rescue_from 挂钩来在应用程序范围内实施后备策略。)

HTH!

【讨论】:

  • 所以每次你去进行更新时,你都会得到对象的当前 lock_version 以及你对它当前状态的请求,很酷。谢谢,我会调查一下
  • 不完全确定您所说的“当前”是什么意思,但听起来不错。看看它,让我知道它对你有什么影响!
  • 对不起,不应该说当前。我了解它已生成,然后发送给请求进行更新的人。然后当用户发送更新时,他们会发送锁定版本,如果他们不匹配,后端知道其他人也在更新中。我做对了吗?我将来会实施这个,但我只是在想当我到达那里时要做什么。谢谢!
  • 你说得对 :) 但是,lock_version 不是生成的,而是保存在数据库中的。每条记录都有自己的 lock_version,每次更新都会递增。
猜你喜欢
  • 2012-04-08
  • 2020-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-14
  • 2021-08-16
  • 2016-04-26
  • 1970-01-01
相关资源
最近更新 更多