У нас есть асинхронная задача, которая выполняет потенциально длительный расчет для объекта. Результат затем кэшируется на объекте. Чтобы предотвратить несколько задач повторять ту же работу, мы добавили замок с атомным обновлением SQL:Имитация условий гонки в модульных тестах RSpec
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. Есть ли способ сделать это? Или есть какая-то другая техника, которую я пропускаю для моделирования таких условий гонки?
A-ha. Это сделало бы это.Хотя вместо того, чтобы добавлять явный крючок, я могу просто использовать 'alias_method_chain' для расширения функциональности метода, который _has_ будет вызываться между двумя семафорами в любом случае - долговременной задачей. – Ian
Ian, Это сделало бы это. –
+1 для использования паразитарной личинки осы в вашем сравнении. – aronchick