[ruby] 루비에서 Ctrl-c 캡처

나는 오래 실행되는 레거시 루비 프로그램을 통과했습니다.

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

편집 :이 코드는 올바르게 트랩하려는 예외의 클래스를 얻는 한 작동합니다. SystemExit, Interrupt 또는 IRB :: Abort는 아래와 같습니다.



답변

문제는 Ruby 프로그램이 종료되면 SystemExit 를 발생시켜 종료한다는 것 입니다. control-C가 들어 오면 Interrupt가 발생 합니다. SystemExitInterrupt 모두 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

사용자 정의 예외는 Exception이 아니라 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!즉시 종료되며 예외가 발생하지 않으므로 코드가 실수로이를 포착 할 수 없습니다.


답변

전체 애플리케이션을 begin ... rescue블록 (예 : Thor)으로 래핑 할 수 없다면 트랩 할 수 있습니다 SIGINT.

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

130은 표준 종료 코드입니다.


답변

나는 ensure큰 효과를 사용 하고 있습니다! 이것은 당신의 물건이 끝나는 이유에 관계없이 당신의 물건이 끝날 때 일어나고 싶은 일을위한 것입니다.


답변

Ruby 에서 ZeroMQ 방식으로 Ctrl-C를 깔끔하게 처리합니다 .

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

출처


답변