Руби: Правильный способ сделать оптимистическую блокировку? - PullRequest
0 голосов
/ 06 октября 2018

Контекст: продукт обновляется несколькими потоками.Так что это приводит к состоянию гонки.Поэтому я использую оптимистическую блокировку, потому что она часто не обновляется.Для последнего обновления состояние продукта определяется атрибутом updated_at.

Например, Prod (id = 1) обновляется в момент времени t1 на машине: 1.Тот же продукт (id = 1) обновляется в момент времени t2 на машине: 2.Теперь состояние Prod (id = 1) на машине: 1 устарело.

Подход Для определения устаревших: я сравню значение updated_at на машине со значением хранилища updated_at в значении базы данных.

Моя главная задача - установить значение @original_updated_at.Должен ли я использовать attr_writer :original_updated_at.Это правильный способ сделать оптимистическую блокировку.

attr_accessor : :original_updated_at
  def original_updated_at
    @original_updated_at || updated_at.to_f
  end


  def stale_object?
    if updated_at.to_f > original_updated_at.to_f
      @original_updated_at = nil
      return true
    else
      @original_updated_at = updated_at.to_f
      return false
    end
  end

  def recalculate
    tries = 0
    begin
      raise Product::StaleObjectError.new("StaleObjectError") if stale_object?
      attributes["updated_at"] = Time.now.utc
      Product.where(:id => self.id).update_all(attributes)
      self.attributes = attributes
    rescue Product::StaleObjectError => e
      if tries < MAX_RETRIES
        tries += 1
        sleep(1 + tries)
        reload
        retry
      else
        raise Product::StaleObjectError("StaleObjectError")
      end
    end
  end

1 Ответ

0 голосов
/ 06 октября 2018

Похоже, вы используете Rails?Не уверен, почему вы пытаетесь свернуть свое собственное решение.Просто добавьте столбец lock_version, чтобы включить оптимистическую блокировку на уровне БД.

https://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html

Также: поскольку вы говорите о нескольких машинах, параллелизм может происходить из нескольких процессов и из нескольких потоков.

Поскольку ваша устаревшая система ломается при добавлениистолбец блокировки некоторые другие решения:

0) Исправить проблемы с оптимистической блокировкой

1) использовать пессимистическую блокировку.В зависимости от сценария загрузки - сколько одновременных операций чтения / записи - это может также работать

2) Исправьте код блокировки (не совсем уверен, как он работает, потому что вы оставляете некоторые детали данного класса))

  • не нужно поднимать, ловить и ре-рейз (просто используйте петлю и break при успехе)
  • вы звоните to_f на поплавках
  • Я не знаю, что self.attributes = attributes должен делать (из кода, который вы показываете, неясно, является ли attributes чем-то иным, чем self.attributes)
  • с использованием отметки времени может или не может бытьдостаточно для определения одновременных обновлений (могут быть сгенерированы две одинаковые метки времени, часы могут быть выключены на нескольких машинах, часы могут быть сброшены или настроены между ними)
  • с использованием sleep - это запах кода

Когда вы пишете такой сложный код, что вам нужно спросить в интернете, работает ли он, то вы, вероятно, идете по неверному пути.Исправьте проблемы с оптимистической блокировкой вместо добавления такого обходного пути.

...