views:

384

answers:

3

I am working on a Rails application where customer refunds are handed to a Sweatshop worker. If a refund fails (because we cannot reach the payment processor at that time) I want to requeue the job.

class RefundWorker < Sweatshop::Worker

def process_refund(job)
  if refund
    Transaction.find(job[:transaction]).update_attributes(:status => 'completed')
  else
    sleep 3
    RefundWorker.async_process_refund(job)   # requeue the job
  end
end

Is there any better way to do this than above? I haven't found any "delay" feature in RabbitMQ, and this is the best solutions I've come up with so far. I want to avoid a busy loop while requeueing.

+1  A: 

Have a timed-delivery service? You'd send the message to deliver as payload, wrapped up with a time-to-deliver, and the service would hold onto the message until the specified time had been reached. Nothing like that exists in the RabbitMQ server or any of the AMQP client libraries, as far as I'm aware, but it'd be a useful thing to have.

Tony Garnock-Jones
celery does this for tasks with an eta/countdown. It just holds on to the messages, and there's a scheduler executing the tasks when the eta is met. As the messages needs to be acknowledged, holding on to them isn't a problem, though it's kinda quirky when using QoS prefetch counts, as we have to increment the prefetch count every time a message with an eta is received, and decrement it when the eta message has been processed.
asksol
+2  A: 

Have you looked at things like Ruote and Minion?

Some links here: http://delicious.com/alexisrichardson/rabbitmq+work+ruby

You could also try Celery which does not speak native Ruby but does speak HTTP+JSON.

All of the above work with RabbitMQ, so may help you.

Cheers

alexis

alexis
Thank you for the alternative clients. I really rather stick to a Ruby one whenever possible and Sweatshop/Carrot has been working great. Their doesn't seem to be a delay function in AMQP, so the re-queue seems the best option at this point. I have the code in development working as I want, just wondering if there wasn't a better way.
Nicholas C
A: 

It doesn't seem like AMQP (or at least RabbitMQ) supports the idea of "delay this job." So the approach to re-queue the same job from inside the worker if it fails seems to be the best solution at this time.

I have the code working in a demo environment and it meeting my needs so far.

Nicholas C