RabbitMQ
다음에 뭔가를 만들면 좀더 그럴싸하게 만들어보고자 !
“웹프론트엔드에서 어떤 요청을 받았는데, 이게 처리가 오래 걸리는 일이다. 이 경우 어떻게 처리하는 것이 좋은가. ” 라는 질문에,
- 쓰레드를 생성해서 일을 시키고, 브라우저에는 빨리 응답을 준다.
- 프로세스를 실행해서 일을 시키고, 브라우저에는 빨리 응답을 준다.
가 당장 떠오르는 방식인데, 이건 뭐, 날코딩으로 모든걸 해결하겠다는거고, 별문제는 없겠지만 그럴싸해보이질 않는다. 해서, 이런저런 해결책을 뒤져보다가 RabbitMQ가 ruby 코드를 지원한다는 것을 발견. (사실 이미 아주 오래전부터 루비 지원하고 있던 거 같은 느낌이…)
게다가 php 도 지원하니까, 프론트엔드를 “개발자가 넘쳐나는” php로 만들고, 뒷단에 long-running 모듈은 내맘대로 아무거로나 짤 수도 있지않을까 공상을 해보았다. (어차피 내가 앞단 뒷단 다 짜면서..)
$ brew install rabbitmq
$ gem install bunny
설명에 따라 실행을 해주고… http://localhost:15672 에 접속해보아 살아있는지 확인.
아래는 메시지 전송기
require "bunny"
conn = Bunny.new(:automatically_recover => false)
conn.start
ch = conn.create_channel
q = ch.queue("backend1")
ch.default_exchange.publish("백엔드 1번 메시지!", :routing_key => q.name)
puts " [x] Sent '백엔드 1번!'"
(1..3).each do |n|
q = ch.queue("backend2")
ch.default_exchange.publish("백엔드 2번 메시지!", :routing_key => q.name)
puts " [x] Sent '백엔드 2번!'"
end
conn.close
여러 개의 큐로 이런 저런 메시지를 보내본다.
아래는 수신기
# encoding: utf-8
require "bunny"
def hi(name)
conn = Bunny.new(:automatically_recover => false)
conn.start
ch = conn.create_channel(nil, 8)
q = ch.queue(name)#, :exclusive => true)
@ii=0
begin
puts " [*] Waiting for messages for #{name}. To exit press CTRL+C"
q.subscribe(:block => false) do |delivery_info, properties, body|
@ii+=1
puts " [x] Received #{name} #{body} #{@ii}"
sleep 9
@ii-=1
puts " end #{@ii}"
end
rescue Interrupt => _
conn.close
exit(0)
end
return q
end
q = hi("backend1")
hi("backend2")
puts "wating messages"
loop do
if q.message_count > 0
msg = q.pop[:payload]
#puts "Found Message: #{msg}"
else
sleep 5
end
end
소스는
여기에서 공식홈페이지 튜토리얼에서 시작해서 (기본 sender와 receiver 소스)
bunny 에 thread pool size 를 넣을 수 있다는 것을 찾아내서 넣고,
여러개의 큐를 하나의 스크립트에서 받게하려고 subscribe(:block=>false) 로 하고, q.pop 으로 데몬흉내
필요하신 분을 위해 소스는 요기에 https://gist.github.com/jinto/97c7a4558fb70d7f33c1
이거 들어가면 그럴싸함을 어느정도 달성할 수 있을듯. 우훗.