Я реализовал Оптимистическую блокировку для состояния гонки.Для этого я добавил дополнительный столбец lock_version
в Product.Метод: recalculate
вызывает private method_1
, затем сохраняет (save!
) продукт.Я не могу использовать save!
в частном порядке method_1
, потому что другие вещи не удастся.Я не хочу перестраивать бизнес-логику.
#Product: Model's new field:
# lock_version :integer(4) default(0), not null
def recalculate
method_1
self.save!
end
private
def method_1
begin
####
####
if self.lock_version == Product.find(self.id).lock_version
Product.where(:id => self.id).update_all(attributes)
else
raise ActiveRecord::StaleObjectError.new(self, "test")
end
rescue ActiveRecord::StaleObjectError => e
if tries < 3
tries += 1
sleep(1 + tries)
self.reload
retry
else
raise Exception.new(timeout.inspect)
end
end
end
Контрольный пример Rspec:
it 'if car is updated then ActiveRecord::StaleObjectError should be raised' do
prod_v1 =Product.find(@prod.id)
prod_v2 = Car.find(@prod.id)
prod_v1.recalculate
prod_v1.reload # will make lock_version of prod_v1 to 1
prod_v2.recalculate # howvever lock_version of prod_v2 is still 0.
expect(car_v2).to receive(:method1).and_raise(ActiveRecord::StaleObjectError)
end
Когда я пытаюсь написать над контрольным примером, он должен вызвать исключение ActiveRecord::StaleObjectError
.Тем не менее, я получаю сообщение об ошибке типа
Failure/Error: expect(car_v2).to receive(:set_total_and_buckets_used).and_raise(ActiveRecord::StaleObjectError)
ArgumentError:
wrong number of arguments (0 for 2)