【发布时间】:2011-01-02 07:41:42
【问题描述】:
我们有一个异步任务,它为一个对象执行可能需要长时间运行的计算。然后将结果缓存在对象上。为了防止多个任务重复相同的工作,我们通过原子 SQL 更新添加了锁定:
UPDATE objects SET locked = 1 WHERE id = 1234 AND locked = 0
锁定仅适用于异步任务。对象本身仍可能由用户更新。如果发生这种情况,旧版本对象的任何未完成任务都应丢弃其结果,因为它们可能已过时。使用原子 SQL 更新也很容易做到这一点:
UPDATE objects SET results = '...' WHERE id = 1234 AND version = 1
如果对象已更新,则其版本将不匹配,因此将丢弃结果。
这两个原子更新应该处理任何可能的竞争条件。问题是如何在单元测试中验证这一点。
第一个信号量很容易测试,因为它只是设置两个不同的测试,有两种可能的情况:(1)对象被锁定的地方和(2)对象没有被锁定的地方。 (我们不需要测试 SQL 查询的原子性,这应该是数据库供应商的责任。)
如何测试第二个信号量?在第一个信号量之后但在第二个信号量之前的某个时间,第三方需要更改对象。这将需要暂停执行,以便可以可靠且一致地执行更新,但我知道不支持使用 RSpec 注入断点。有没有办法做到这一点?或者是否有其他一些我忽略的技术来模拟这种竞争条件?
【问题讨论】:
标签: ruby-on-rails ruby unit-testing rspec race-condition