Capturing Ctrl-c in ruby

前端 未结 5 1633
慢半拍i
慢半拍i 2020-12-02 06:02

I was passed a long running legacy ruby program, which has numerous occurrences of

begin
  #dosomething
rescue Exception => e
  #halt the exception\'s pr         


        
相关标签:
5条回答
  • 2020-12-02 06:24

    The problem is that when a Ruby program ends, it does so by raising SystemExit. When a control-C comes in, it raises Interrupt. Since both SystemExit and Interrupt derive from Exception, your exception handling is stopping the exit or interrupt in its tracks. Here's the fix:

    Wherever you can, change

    rescue Exception => e
      # ...
    end
    

    to

    rescue StandardError => e
      # ...
    end
    

    for those you can't change to StandardError, re-raise the exception:

    rescue Exception => e
      # ...
      raise
    end
    

    or, at the very least, re-raise SystemExit and Interrupt

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

    Any custom exceptions you have made should derive from StandardError, not Exception.

    0 讨论(0)
  • 2020-12-02 06:27

    If you can't wrap your whole application in a begin ... rescue block (e.g., Thor) you can just trap SIGINT:

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

    130 is a standard exit code.

    0 讨论(0)
  • 2020-12-02 06:31

    If you can wrap your whole program you can do something like the following:

     trap("SIGINT") { throw :ctrl_c }
    
     catch :ctrl_c do
     begin
        sleep(10)
     rescue Exception
        puts "Not printed"
     end
     end
    

    This basically has CtrlC use catch/throw instead of exception handling, so unless the existing code already has a catch :ctrl_c in it, it should be fine.

    Alternatively you can do a trap("SIGINT") { exit! }. exit! exits immediately, it does not raise an exception so the code can't accidentally catch it.

    0 讨论(0)
  • 2020-12-02 06:33

    Handling Ctrl-C cleanly in Ruby the ZeroMQ way:

    #!/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
    

    Source

    0 讨论(0)
  • 2020-12-02 06:39

    I am using ensure to great effect! This is for things you want to have happen when your stuff ends no matter why it ends.

    0 讨论(0)
提交回复
热议问题