Захват Ctrl-c в рубине
Мне была передана давно запущенная рубиновая программа, которая имеет многочисленные вхождения
begin
#dosomething
rescue Exception => e
#halt the exception progress
end
во всем этом.
Не отслеживая каждое возможное исключение, каждое из них может обрабатываться (по крайней мере, не сразу), я все равно хотел бы время от времени закрывать его с помощью Ctrl C.
И я хотел бы сделать это таким образом, который добавит только код (поэтому я не влияю на существующее поведение или не пропущу исключение, исключенное иначе в середине прогона.)
[Ctrl C - это SIGINT или SystemExit, который, как представляется, эквивалентен SignalException.new("INT")
в системе обработки исключений Ruby. class SignalException < Exception
, поэтому эта проблема возникает.]
Код, который я хотел бы написать, будет:
begin
#dosomething
rescue SignalException => e
raise e
rescue Exception => e
#halt the exception progress
end
РЕДАКТИРОВАТЬ: Этот код работает, если вы получите класс исключения, который вы хотите уловить. Это либо SystemExit, Interrupt, либо IRB:: Abort, как показано ниже.
Ответы
Ответ 1
Проблема в том, что когда программа Ruby заканчивается, она делает это, поднимая SystemExit. Когда включается элемент управления-C, он вызывает прерывание. Поскольку как SystemExit, так и Interrupt производятся от Exception, ваша обработка исключений останавливает выход или прерывание на своих дорожках. Здесь исправление:
Везде, где вы можете, измените
rescue Exception => e
# ...
end
to
rescue StandardError => e
# ...
end
для тех, которые вы не можете изменить в StandardError, переподготовьте исключение:
rescue Exception => e
# ...
raise
end
или, по крайней мере, повторно поднять SystemExit и прерывание
rescue SystemExit, Interrupt
raise
rescue Exception => e
#...
end
Любые пользовательские исключения, которые вы сделали, должны выводиться из StandardError, а не из Exception.
Ответ 2
Если вы можете обернуть всю вашу программу, вы можете сделать что-то вроде следующего:
trap("SIGINT") { throw :ctrl_c }
catch :ctrl_c do
begin
sleep(10)
rescue Exception
puts "Not printed"
end
end
В основном это Ctrl C использует catch/throw вместо обработки исключений, поэтому, если существующий код уже не имеет catch: ctrl_c в нем, это должно быть хорошо.
В качестве альтернативы вы можете сделать trap("SIGINT") { exit! }
. exit!
выходит немедленно, он не вызывает исключения, поэтому код не может случайно его поймать.
Ответ 3
Если вы не можете обернуть все ваше приложение в блок begin ... rescue
(например, Thor), вы можете просто уловить SIGINT
:
trap "SIGINT" do
puts "Exiting"
exit 130
end
130 - стандартный код выхода.
Ответ 4
Я использую ensure
для отличного эффекта! Это для вещей, которые вы хотите, когда ваши вещи заканчиваются независимо от того, почему они заканчиваются.