Ruby, windows, active_record и Control-C
Что делает active_record с сигнальными процессами под Windows (я не вижу этого с теми же версиями на Mac), что заставляет его вести себя так странно? Например:
require 'rubygems'
trap("INT"){puts "interrupted"}
puts __LINE__
sleep 5
require 'active_record'
trap("INT"){puts "interrupted again"}
puts __LINE__
sleep 5
Когда я запускаю приведенный выше код (ruby 1.8.6, gem 1.3.1, activerecord 2.2.2,), я могу нажимать ^C столько раз, сколько мне нравится во время первого сна, но первое прерывание после требования activerecord вызывает скрипт для прекращения. В вышеприведенном случае ловушка все еще выполняется, она только не позволяет программе продолжаться. Обычно.
Удаление второго вызова trap не влияет на поведение.
Настоящее раздражение в том, что в некоторых условиях ловушка вообще не срабатывает. Учитывая, что весь смысл в этом состоит в том, чтобы заставить мой код очищаться после себя (удалить его след в базе данных, чтобы следующий парень увидел нормальное состояние), это реальная проблема. Например:
require 'rubygems'
require 'active_record'
trap("INT"){puts "interrupted"}
puts __LINE__
gets
Нажатие ^C после просмотра пут не будет вообще выполнять ловушку.
Я вижу эту проблему только после запроса active_record. Есть ли обходной путь? Мне было бы интересно узнать, если это ошибка или есть какое-то объяснение. Как я уже сказал, у меня нет проблем с этим на Mac - повторяющиеся ^Cs приводят к многократному выполнению процесса trap.
Спасибо...
2 ответа
Учитывая, что весь смысл в этом состоит в том, чтобы заставить мой код очищаться после себя (удалить его след в базе данных...
Рассматривали ли вы просто использование транзакции базы данных? Кажется, что это был бы гораздо более простой способ решить проблему.
Я увидел другую картину при попытке дублировать эту проблему:
puts "start"
trap("INT") { puts "interrupted" }
sleep 5
puts "end"
На Ubuntu (Ruby 1.8.6) это производит
start
interrupted
interrupted
(etc)
interrupted
end
Таким образом, "прерванные" отпечатки каждый раз, когда нажимается Crtl-C, до тех пор, пока не истечут 5 секунд. Под Windows (также Ruby 1.8.6) это производит:
start
interrupted
end
то есть он печатает "прерванный" один раз и затем выходит.
Таким образом, кажется, что при обработке SIGINT Ruby выходит из режима сна и переходит к следующему оператору. Я предполагаю (махнув рукой), что это связано с тем, что Ruby использует зеленые потоки вместо собственных потоков в Windows. Любые эксперты, пожалуйста, перезвоните здесь.
Вы можете эмулировать поведение Unix-y, перезапустив sleep
в обработчике:
puts "start"
trap("INT") do
puts "interrupted"
sleep 5
end
sleep 5
puts "end"
К сожалению, это сбрасывает таймер каждый раз, когда SIGINT перехватывается, поэтому он требует некоторого взлома:
$interval = 5
def go_to_sleep(secs)
$started = Time.now
sleep secs
end
trap("INT") do
puts "interrupted"
time_to_sleep = [0,$interval - (Time.now - $started)].max
if time_to_sleep > 0
sleep time_to_sleep
end
end
puts "one"
go_to_sleep($interval)
puts "two"
go_to_sleep($interval)
puts "three"
go_to_sleep($interval)