我们有一个异步任务,它为对象执行可能长时间运行的计算。然后将结果缓存在对象上。为了防止多个任务重复相同的工作,我们通过原子 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 注入断点。有没有办法做到这一点?还是有一些我忽略的其他技术来模拟这种竞争条件?