Как убедиться, что одновременно работает только один экземпляр сценария Ruby? - PullRequest
8 голосов
/ 19 марта 2009

У меня есть процесс, который запускается на cron каждые пять минут. Обычно для запуска требуется всего несколько секунд, но иногда это занимает несколько минут. Я хочу убедиться, что одновременно работает только одна версия.

Я попробовал очевидный способ ...

File.open("/tmp/indexer_lock.tmp",'w') do |f|
  exit unless f.flock(File::LOCK_EX)
end

... но он не проверяет, сможет ли он получить блокировку, он блокируется до тех пор, пока блокировка не будет снята.

Есть идеи, что мне не хватает? Я бы предпочел не взламывать что-либо с помощью PS, но это альтернатива.

Ответы [ 9 ]

23 голосов
/ 01 декабря 2010

Я знаю, что это старая версия, но для всех, кто интересуется, есть неблокирующая константа, которую вы можете передать стаду, чтобы она возвращалась вместо блокировки.

File.new("/tmp/foo.lock").flock( File::LOCK_NB | File::LOCK_EX )

Обновление для slhck

flock вернет true, если этот процесс получил блокировку, иначе false. Таким образом, чтобы убедиться, что одновременно запущен только один процесс, вам нужно просто попытаться получить блокировку и выйти, если вы не смогли этого сделать. Это так же просто, как поставить exit unless перед строкой кода, которую я имею выше:

exit unless File.new("/tmp/foo.lock").flock( File::LOCK_NB | File::LOCK_EX )
4 голосов
/ 02 февраля 2011

В зависимости от ваших потребностей, это должно работать нормально и не требует создания другого файла.

exit unless DATA.flock(File::LOCK_NB | File::LOCK_EX)

# your script here

__END__
DO NOT REMOVE: required for the DATA object above.
3 голосов
/ 19 марта 2009

Для этой ситуации есть гем-файл блокировки . Я использовал это раньше, и это очень просто.

3 голосов
/ 19 марта 2009

Хотя это не дает прямого ответа на ваш вопрос, на вашем месте я, вероятно, написал бы сценарий демона (вы можете использовать http://daemons.rubyforge.org/)

Вы можете запустить индексатор (при условии его indexer.rb) через скрипт-обертку с именем script / index, например:

require 'rubygems'
require 'daemons'

Daemons.run('indexer.rb')

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

loop do
   # code executing your indexing 

   sleep INDEXING_INTERVAL
end

Так обычно работают рабочие процессоры в тандеме с сервером очередей.

3 голосов
/ 19 марта 2009

Вы можете создать и удалить временный файл и проверить его наличие. Пожалуйста, проверьте ответ на этот вопрос: один экземпляр сценария оболочки

2 голосов
/ 19 марта 2009

Если вы используете cron, может быть проще сделать что-то подобное в сценарии оболочки, который cron вызывает:

#!/usr/local/bin/bash
#

if ps -C $PROGRAM_NAME &> /dev/null ; then
   : #Program is already running.. appropriate action can be performed here (kill it?)
else
   #Program is not running.. launch it.
   $PROGRAM_NAME
fi
1 голос
/ 19 марта 2009

Хорошо, отработка заметок от указателя @ shodanex, вот что у меня есть. Я немного его натер (хотя я не знаю о сенсорном аналоге в Ruby).

tmp_file = File.expand_path(File.dirname(__FILE__)) +  "/indexer.lock"
if File.exists?(tmp_file)
  puts "quitting"
  exit
else
  `touch #{tmp_file}`
end

.. do stuff ..

File.delete(tmp_file)
0 голосов
/ 17 марта 2011

На более высоком уровне вам может пригодиться камень lock_method :

def the_method_my_cron_job_calls
  # something really expensive
end
lock_method :the_method_my_cron_job_calls

По умолчанию он использует файлы блокировки, хранящиеся в локальной файловой системе (о чем говорилось выше), но вы также можете настроить хранилище удаленной блокировки:

LockMethod.config.storage = Redis.new([...]) # a remote RedisToGo instance, perhaps?

Кроме того ...

def the_method_my_cron_job_calls
  # something really expensive
end
lock_method :the_method_my_cron_job_calls, (60*60) # automatically expire lock after an hour
0 голосов
/ 19 марта 2009

Не можете ли вы добавить File :: LOCK_NB в свою блокировку, чтобы сделать ее неблокируемой (то есть она не работает, если не может получить блокировку)

Это будет работать в C, Perl и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...