XMLRPC::Server를 Thread 안에서 돌릴 경우, SIGINT 처리가 이상합니다.

55 views
Skip to first unread message

Nidev Plontra

unread,
Jan 27, 2015, 7:40:53 AM1/27/15
to rub...@googlegroups.com
# encoding: utf-8
#

require "xmlrpc/server"

$thread
= Thread.new {
  puts
"Server starts"
  rpcd
= XMLRPC::Server.new
  rpcd
.serve
  puts
"Server stopped"
}

$thread
.run

puts
"Wait 30 seconds in main thread"
sleep
30
puts
"Done"

안녕하세요.

XMLRPC 서버와 데이터 처리 작업을 한 프로세스 안에서 병행하기 위해 루비 프로그램을 설계하였고, 위의 코드처럼 메인과 XMLRPC서버를 돌리는 쓰레드로 나눠져있습니다.

만약에 SIGINT가 들어올 경우, 쓰레드에서 돌리던 서버와 메인 쓰레드가 한번에 (동시에는 어렵겠지만) 종료되어 셸로 돌아가는 것을 원하고 있습니다.

따라서 제가 예상하는 출력은 다음과 같습니다.

(셸에서 루비 코드를 실행)
Wait 30 seconds in main thread
Server starts

[2015-01-27 21:29:36] INFO  WEBrick 1.3.1
[2015-01-27 21:29:36] INFO  ruby 2.1.0 (2015-01-26) [x86_64-linux-gnu]
[2015-01-27 21:29:36] INFO  WEBrick::HTTPServer#start: pid=6082 port=8080
^C
(Interrupt 예외에 대한 오류가 뜨거나, 소리 없이 셸로 돌아옴)

^C를 누르는 시점은 WEBrick이 완전히 가동된 시점입니다. 그러나, 제 가정과는 다르게 ^C는 WEBrick 만 종료시켰고, sleep 30은 계속 진행되고있었으며 다시 ^C를 눌러도 메인 쓰레드에는 전혀 영향을 주지 못하고 있었습니다.

해당 상황은 MRI 2.1.0과 2.2.0 양쪽에서 모두 발생하고 있습니다.

그러나 Rubinius 에서는 동작이 또 다릅니다. ^C를 WEBrick이 가동된 후에 누르면, sleep 30은 아무런 Exception 없이 중단되고 그 다음 코드인 puts "Done"가 실행되고 조용히 셸로 돌아옵니다.

ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]
rubinius
2.5.1 (2.1.0 8fd046f3 2015-01-26 3.5.1 JI) [x86_64-linux-gnu]


Signal.trap() 등을 사용해 SIGINT를 처리해보려고 했으나 상황에 진전이 없어서 루비 사용자 모임에 올리게 되었습니다.

MRI의 버그인지, 아니면 쓰레드 모델 때문에 제가 프로그램 구조를 바꿔야하는 상황인지 궁금합니다.

최명진

unread,
Jan 27, 2015, 7:46:54 AM1/27/15
to rub...@googlegroups.com
webrick대신에 thin이나 unicorn 을 쓰면 어떠세요?


Mailbox에서 보냄


--

---
이 메일은 Google 그룹스 '한국 루비 사용자 모임' 그룹에 가입한 분들에게 전송되는 메시지입니다.
이 그룹에서 탈퇴하고 더 이상 이메일을 받지 않으려면 rubykr+un...@googlegroups.com에 이메일을 보내세요.
http://groups.google.com/group/rubykr에서 이 그룹을 방문하세요.
더 많은 옵션을 보려면 https://groups.google.com/d/optout을(를) 방문하세요.

Nidev Plontra

unread,
Jan 27, 2015, 7:57:55 AM1/27/15
to rub...@googlegroups.com
thin이나 unicorn 모두 레일즈에서는 굉장히 유용한 것 같은데, 제가 필요한 것은 XMLRPC이고 루비가 표준 라이브러리 단에서 XMLRPC를 지원하고 있어서 최대한 이용하고자 합니다.

그런데 표준 라이브러리의 XMLRPC서버는 WEBrick으로 동작하고 있어서 제가 무언가 대체하기가 어려운 것 같습니다.

2015년 1월 27일 화요일 오후 9시 46분 54초 UTC+9, 최피디 님의 말:

Nidev Plontra

unread,
Jan 27, 2015, 8:55:41 AM1/27/15
to rub...@googlegroups.com
module XMLRPC
 
# Copy from ruby stdlib 2.2.0
 
class ServerNoTrap < XMLRPC::WEBrickServlet
   
def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a)
     
super(*a)
     
require 'webrick'
     
@server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections,
                                       
:Logger => WEBrick::Log.new(stdlog))
     
@server.mount("/", self)
   
end

   
# Call this after you have added all you handlers to the server.
   
# This method starts the server to listen for XML-RPC requests and answer them.
   
def serve
     
#signals = %w[INT TERM HUP] & Signal.list.keys
     
#signals.each { |signal| trap(signal) { @server.shutdown } }

     
@server.start
   
end

   
# Stops and shuts the server down.
   
def shutdown
     
@server.shutdown
   
end

 
end
end

최피디님의 이야기가 좋은 힌트가 되었습니다.

http 서버 교체가 어려우면 표준 라이브러리쪽 코드를 고치려고 직접 xmlrpc/server.rb 가 있는 폴더를 보았더니, serve 메소드 안에 signal trap 을 설치하는 부분이 보였습니다.

그래서 이것을 주석처리한 XMLRPC::Server 구현을 XMLRPC::ServerNoTrap 으로 선언하고 돌려보니 SIGINT가 들어오면 WEBrick도 정상적으로 닫히고 메인 쓰레드의 프로그램도 인터럽트 됩니다.

이후에 사용하실 분을 위하여 XMLRPC::ServerNoTrap 을 코드로 올려둡니다.

감사합니다.

2015년 1월 27일 화요일 오후 9시 57분 55초 UTC+9, Nidev Plontra 님의 말:
Reply all
Reply to author
Forward
0 new messages