2014-05-03 23 views
5

Rabbit gem için Bunny gemini Rails ile entegre ediyorum, Bunny thread'ı başlatmaya başladığında bir raptiye başladım. Rails, uygulamanın başlamasına veya ayrı bir komisyon görevinde başlamasına izin verebilir. ayrı bir süreçte?Rails and Thin'da tavşan ipliği nasıl başlatılır

Sadece ileti üretiyorsam, Rails başlatıcısında uygulamam gerekiyor, bu yüzden uygulamayı allover olarak kullanabilirim, ancak tüketirsem, ayrı bir komisyon görevinde yapmalıyım, bu doğru mu? ?

cevap

5

Haklısınız: Rails uygulamasından kendiniz tüketilmemelisiniz. Rails uygulamasının bir yapımcı olması gerekir; bu durumda, bir başlatıcı, Bunny örneğini başlatmak için doğru yerdir.

# config/initializers/bunny.rb 
MESSAGING_SERVICE = MessagingService.new(ENV.fetch("AMQP_URL")) 
MESSAGING_SERVICE.start 

# app/controllers/application_controller.rb 
class ApplicationController 
    def messaging_service 
    MESSAGING_SERVICE 
    end 
end 

# app/controllers/uploads_controller.rb 
class UploadsController < ApplicationController 
    def create 
    # save the model 
    messaging_service.publish_resize_image_request(model.id) 
    redirect_to uploads_path 
    end 
end 

# lib/messaging_service.rb 
class MessagingService 
    def initialize(amqp_url) 
    @bunny = Bunny.new(amqp_url) 
    @bunny.start 
    at_exit { @bunny.stop } 
    end 

    attr_reader :bunny 

    def publish_resize_image_request(image_id) 
    resize_image_exchange.publish(image_id.to_s) 
    end 

    def resize_image_exchange 
    @resize_image_exchange ||= 
     channel.exchange("resize-image", passive: true) 
    end 

    def channel 
    @channel ||= bunny.channel 
    end 
end 

mesajları tüketen, ben dahil Rake olmadan yürütülebilir başlatmayı tercih:

Ben esasen RabbitMQ mesajlar yayınlamak benim Raylar uygulamalarda bu kodu var. Rake daha fazla bellek kullanacak yeni bir süreci çatallayacaktır.

# bin/image-resizer-worker 
require "bunny" 
bunny = Bunny.new(ENV.fetch("AMQP_URL")) 
bunny.start 
at_exit { bunny.stop } 

channel = bunny.channel 

# Tell RabbitMQ to send this worker at most 2 messages at a time 
# Else, RabbitMQ will send us as many messages as we can absorb, 
# which would be 100% of the queue. If we have multiple worker 
# instances, we want to load-balance between each of them. 
channel.prefetch(2) 

exchange = channel.exchange("resize-image", type: :direct, durable: true) 
queue = channel.queue("resize-image", durable: true) 
queue.bind(exchange) 
queue.subscribe(manual_ack: true, block: true) do |delivery_info, properties, payload| 
    begin 
    upload = Upload.find(Integer(payload)) 
    # somehow, resize the image and/or post-process the image 

    # Tell RabbitMQ we processed the message, in order to not see it again 
    channel.acknowledge(delivery_info.delivery_tag, false) 

    rescue ActiveRecord::RecordNotFound => _ 
    STDERR.puts "Model does not exist: #{payload.inspect}" 
    # If the model is not in the database, we don't want to see this message again 
    channel.acknowledge(delivery_info.delivery_tag, false) 

    rescue Errno:ENOSPC => e 
    STDERR.puts "Ran out of disk space resizing #{payload.inspect}" 
    # Do NOT ack the message, in order to see it again at a later date 
    # This worker, or another one on another host, may have free space to 
    # process the image. 

    rescue RuntimeError => e 
    STDERR.puts "Failed to resize #{payload}: #{e.class} - #{e.message}" 
    # The fallback should probably be to ack the message. 
    channel.acknowledge(delivery_info.delivery_tag, false) 
    end 
end 

bile, önceden oluşturulmuş taşlar ve Rails'in soyutlama, ActiveJob kullanarak daha iyi olabilir hepsi göz önüne alındığında.

+0

Neden "MESSAGING_SERVICE.start" ikinci kez arıyorsun? MessagingService'de zaten başladı. – sekrett