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