Как я могу заблокировать набор объектов для операции? - PullRequest
5 голосов
/ 24 марта 2011

В моем приложении rails у меня есть такой код:

def foo
  if object_bar_exists
    raise "can't create bar twice!"
  end

  Bar.create
end

Который может вызываться двумя разными запросами, поступающими на сервер приложений. Если этот код выполняется двумя запросами одновременно, и оба они одновременно запускают проверку if, ни один из них не найдет bar другого, и будет создано 2 bar s.

Какой лучший способ создать «мьютекс» для «коллекции баров»? Таблица мьютексов специального назначения в БД?

обновление

Я должен подчеркнуть, что я не могу использовать здесь мьютекс памяти, потому что параллелизм выполняется между запросами / процессами, а не потоками.

Ответы [ 3 ]

6 голосов
/ 24 марта 2011

Лучшее, что можно сделать - это выполнить свои операции в транзакции с БД. Поскольку у вас, вероятно, в конечном итоге будет запущено несколько приложений, и они, вероятно, не будут совместно использовать память, вы не сможете создать блокировку Mutex на уровне приложений, особенно если эти две службы приложений работают в совершенно разных физических блоках. Вот как выполнить транзакцию с БД:

ActiveRecord::Base.transaction do
  # Transaction code goes here.
end

Если вы хотите обеспечить откат транзакции БД, вам нужно включить проверку для класса Bar, чтобы неправильный запрос на сохранение вызвал откат:

ActiveRecord::Base.transaction do
  bar = Bar.new(params[:bar])
  bar.save!
end

Если у вас уже есть объект bar в БД, вы можете пессимистически заблокировать этот объект следующим образом:

ActiveRecord::Base.transaction do
  bar = Bar.find(1, :lock => true)
  # perform operations on bar
end
1 голос
/ 24 марта 2011

Если все запросы поступают на одну и ту же машину и одну и ту же виртуальную машину ruby, вы можете использовать встроенный в Ruby класс Mutex: Документы Mutex .

Если имеется несколько машин или rvms, вам придется использовать транзакцию базы данных для создания / получения объекта Bar, предполагая, что он каким-то образом хранится в БД.

0 голосов
/ 24 марта 2011

Я бы, вероятно, создал бы объект Singleton в каталоге lib, чтобы у вас был только один экземпляр этой вещи, и использовал бы Mutexes для его блокировки.

Таким образом, вы можете обеспечить только один доступ к вещи в любой момент времени.Конечно, любые другие запросы будут блокировать его, так что об этом следует помнить.

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

...