Как создать перезагружаемый «процесс» или «поток» в Ruby? - PullRequest
0 голосов
/ 25 января 2010

У меня есть этот скрипт, который загружает некоторые файлы, подключается через ssh и делает что-то на удаленном сервере, что-то вроде скрипта развертывания, и я хочу, чтобы он запускался всякий раз, когда я хочу, и чтобы я мог его сбросить в середине обработки.

def deploy
  # some stuff happens here
end

def do_deploy
   $deploy.kill! if $deploy
   $deploy = Thread.new { deploy }
   $deploy.join  # when I don't have the join here, it stop executing the deploy
                 # like after first when thread switches to something else, and
                 # then never finishes
end

reading = Thread.new do
  while line = gets.chomp!
    case line
    when "q" then
      puts "exiting"
      Thread.exit
      exit
    when "r" then
      do_deploy
    end
  end
end

reading.join

Несмотря на то, что $deploy.join выполняет весь поток развертывания, он предотвращает чтение любого ввода, поэтому я не могу сбросить его в середине выполнения. И я не могу присоединиться к нему в конце сценария.

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

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

Я также хотел бы отметить, что я работаю в Windows, поэтому у меня нет fork() в наличии.

Есть ли другой способ, как решить эту проблему без потоков?

edit: Только что выяснилось, что вызов gets блокирует выполнение всех других потоков до тех пор, пока не будет дан какой-либо ввод В этом примере

t1 = Thread.new { 10.times { |i| puts i } }
t2 = Thread.new { puts gets }
t1.join
t2.join

t1 не будет выполнен, пока я не введу gets. Он просто сидит там вечно. Как читать с ввода, не блокируя все потоки?

edit2: только что выяснил, что это проблема, связанная с Windows

edit3: проблема исчезла в JRuby или Ruby 1.9

Ответы [ 2 ]

0 голосов
/ 25 января 2010

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

Поток deploy должен выполняться, как только вы вызовете Thread.new. Если я правильно читаю ваш код, вы хотите переместить ваш вызов на .join изнутри do_deploy внутрь вашего блока reading. Попробуйте использовать следующее для вашего reading блока (у меня нет Ruby передо мной, так что это может быть не идеальный синтаксис):

reading = Thread.new do
  while line = gets.chomp!
    case line
    when "q" then
      puts "exiting"
      $deploy.kill if $deploy
      break
    when "r" then
      do_deploy
    end
  end
  $deploy.join
end

Это должно запустить (или уничтожить и перезапустить) процесс deploy, когда вводится «r», а затем вернуться в цикл обработки ввода. Введите «q», и процессу deploy будет отправлен сигнал «завершение», и цикл обработки ввода будет ожидать его завершения, прежде чем завершится сам.

С потоками Ruby вы можете столкнуться с проблемами, когда кажется, что поток обработки ввода не работает, когда работает поток deploy (занятые потоки могут истощить потоки с низким приоритетом). Если это произойдет с вами, я бы порекомендовал добавить некоторые явные вызовы к Thread.pass в вашей подпрограмме deploy. Это заставит планировщик потока запускать другой поток. Вы также можете поэкспериментировать с использованием приоритетов потоков и размещением потока обработки ввода с более высоким приоритетом, чем ваш рабочий поток.

0 голосов
/ 25 января 2010

Используйте JRuby. Он имеет реальные потоки и не становится жертвой GIL (Global Interpreter Lock), который есть у интерпретатора C Ruby.

http://www.jruby.org/

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