У нас есть асинхронная задача, которая выполняет потенциально длительный расчет для объекта. Результат затем кэшируется на объекте. Чтобы предотвратить повторение одной и той же работы несколькими задачами, мы добавили блокировку с помощью атомного обновления 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. Есть ли способ сделать это? Или есть какая-то другая техника, которую я пропускаю для моделирования таких условий гонки?