Захват Ctrl-c в ruby
мне передали давно запущенную программу legacy ruby, которая имеет множество вхождений
begin
#dosomething
rescue Exception => e
#halt the exception's progress
end
на всем ее протяжении.
не отслеживая каждое возможное исключение, каждое из которых может быть обработано (по крайней мере, не сразу), я все равно хотел бы иметь возможность закрыть его время от времени с CtrlC.
и я хотел бы сделать это таким образом, который только добавляет к коду (так что я не влияю на существующее поведение, или пропустить в противном случае поймал исключение в программе.)
[CtrlC - это SIGINT, или SystemExit, который, по-видимому, эквивалентен SignalException.new("INT")
в системе обработки исключений Ruby. class SignalException < Exception
, вот почему эта проблема возникает.]
код, который я хотел бы, написал бы:
begin
#dosomething
rescue SignalException => e
raise e
rescue Exception => e
#halt the exception's progress
end
EDIT: этот код работает, пока вы получаете класс исключения, которое вы хотите поймать правильно. Это либо SystemExit, прерывание, либо IRB:: прервать, как показано ниже.
4 ответа:
проблема в том, что когда программа Ruby заканчивается, она делает это, поднимая SystemExit. Когда приходит control-C, он поднимает отмена. Так как SystemExit и отмена выводим из исключение, ваша обработка исключений останавливает выход или прерывание на своих дорожках. Вот исправление:
везде, где вы можете, изменить
rescue Exception => e # ... end
до
rescue StandardError => e # ... end
для тех, Вы не можете изменить чтобы StandardError, повторно поднять исключение:
rescue Exception => e # ... raise end
или, по крайней мере, повторно поднять SystemExit и прервать
rescue SystemExit, Interrupt raise rescue Exception => e #... end
любые пользовательские исключения, которые вы сделали, должны быть получены из StandardError, а не исключение.
Если вы можете обернуть всю программу, вы можете сделать что-то вроде следующего:
trap("SIGINT") { throw :ctrl_c } catch :ctrl_c do begin sleep(10) rescue Exception puts "Not printed" end end
Это в основном имеет CtrlC используйте catch / throw вместо обработки исключений, поэтому, если в существующем коде уже есть catch :ctrl_c, это должно быть нормально.
можно сделать
trap("SIGINT") { exit! }
.exit!
немедленно завершает работу, он не вызывает исключение, поэтому код не может случайно поймать его.