Захват Ctrl-C в рубине - PullRequest
       43

Захват Ctrl-C в рубине

100 голосов
/ 19 января 2010

Мне передали давно запущенную унаследованную программу ruby, которая имеет многочисленные случаи

begin
  #dosomething
rescue Exception => e
  #halt the exception's 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's progress
end

РЕДАКТИРОВАТЬ: Этот код работает, пока вы получаете класс исключения, которое вы хотите перехватить правильно. Это либо SystemExit, либо Interrupt, либо IRB :: Abort, как показано ниже.

Ответы [ 5 ]

122 голосов
/ 19 января 2010

Проблема в том, что когда программа Ruby завершается, она делает это, вызывая SystemExit .Когда входит элемент управления C, он вызывает Interrupt .Так как SystemExit и Прерывание являются производными от Exception , ваша обработка исключений останавливает выход или прерывание в его дорожках.Вот исправление:

Везде, где вы можете, измените

rescue Exception => e
  # ...
end

на

rescue StandardError => e
  # ...
end

для тех, кого вы не можете изменить на StandardError, повторно вызовите исключение:

rescue Exception => e
  # ...
  raise
end

или, по крайней мере, повторно вызвать SystemExit и Interrupt

rescue SystemExit, Interrupt
  raise
rescue Exception => e
  #...
end

Любые сделанные вами пользовательские исключения должны происходить из StandardError , а не Исключение .

68 голосов
/ 19 января 2010

Если вы можете обернуть всю свою программу, вы можете сделать что-то вроде следующего:

 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! завершается немедленно, оно не вызывает исключения, поэтому код не может случайно его перехватить.

31 голосов
/ 23 мая 2014

Если вы не можете обернуть все приложение в блок begin ... rescue (например, Тор), вы можете просто перехватить SIGINT:

trap "SIGINT" do
  puts "Exiting"
  exit 130
end

130 - это стандартный код выхода.

4 голосов
/ 25 ноября 2015

Я использую ensure с большим эффектом! Это для вещей, которые вы хотите, чтобы ваши вещи заканчивались, независимо от того, почему они заканчиваются.

0 голосов
/ 28 декабря 2018

Чистая обработка Ctrl-C в Ruby способом ZeroMQ:

#!/usr/bin/env ruby

# Shows how to handle Ctrl-C
require 'ffi-rzmq'

context = ZMQ::Context.new(1)
socket = context.socket(ZMQ::REP)
socket.bind("tcp://*:5558")

trap("INT") { puts "Shutting down."; socket.close; context.terminate; exit}

puts "Starting up"

while true do
  message = socket.recv_string
  puts "Message: #{message.inspect}"
  socket.send_string("Message received")
end

Источник

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