Capturando Ctrl-c en ruby
Se me pasó un programa ruby heredado de larga duración, que tiene numerosas ocurrencias de
begin
#dosomething
rescue Exception => e
#halt the exception's progress
end
A lo largo de ella.
Sin rastrear todas las excepciones posibles, cada una de ellas podría estar manejando (al menos no inmediatamente), todavía me gustaría poder apagarlo a veces con CtrlC.
Y me gustaría hacerlo de una manera que solo se agrega al código (para que no afecte el comportamiento existente, o se pierda una excepción atrapada en el medio de una carrera.)
[CtrlC es SIGINT, o SystemExit, que parece ser equivalente a SignalException.new("INT")
en el sistema de manejo de excepciones de Ruby. class SignalException < Exception
, por lo que surge este problema.]
El código que me gustaría haber escrito sería:
begin
#dosomething
rescue SignalException => e
raise e
rescue Exception => e
#halt the exception's progress
end
EDITAR: Este código funciona, siempre y cuando obtenga la clase de la excepción que desea atrapar correcta. Eso es SystemExit, Interrupt o IRB:: Abort como se muestra a continuación.
4 answers
El problema es que cuando un programa Ruby termina, lo hace levantando SystemExit. Cuando entra un control-C, levanta Interrupt . Dado que tanto SystemExitcomo Interruptderivan de Exception, su manejo de excepciones detiene la salida o interrupción en sus pistas. Aquí está la solución:
Donde puedas, cambia
rescue Exception => e
# ...
end
A
rescue StandardError => e
# ...
end
Para aquellos que no puede cambiar a StandardError, vuelva a levantar el excepción:
rescue Exception => e
# ...
raise
end
O, como mínimo, volver a elevar SystemExit e Interrumpir
rescue SystemExit, Interrupt
raise
rescue Exception => e
#...
end
Cualquier excepción personalizada que haya hecho debe derivar de StandardError, no Exception.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-06 13:36:54
Si puedes envolver todo tu programa puedes hacer algo como lo siguiente:
trap("SIGINT") { throw :ctrl_c }
catch :ctrl_c do
begin
sleep(10)
rescue Exception
puts "Not printed"
end
end
Esto básicamente tiene CtrlC use catch/throw en lugar de exception handling, así que a menos que el código existente ya tenga un catch :ctrl_c en él, debería estar bien.
Alternativamente puede hacer un trap("SIGINT") { exit! }
. exit!
sale inmediatamente, no genera una excepción por lo que el código no puede atraparlo accidentalmente.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-18 04:52:03
Si no puedes envolver toda tu aplicación en un bloque begin ... rescue
(por ejemplo, Thor) puedes simplemente atrapar SIGINT
:
trap "SIGINT" do
puts "Exiting"
exit 130
end
130 es un código de salida estándar.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-23 16:26:35
Estoy usando ensure
con gran efecto! Esto es para las cosas que quieres que sucedan cuando tus cosas terminen sin importar por qué terminen.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-24 23:52:56