Twilio - delayed job, cron job, or worker or what?
I am building an app that is using Twilio and we need to call Twilio's server a certain period after the call starts.
I'm using RoR and right now its on Heroku, but we can move it elsewhere if need be.
I've looked at Delayed Jobs and Cron jobs but I don't know enough about it to know which route I should take.
Seems like Delayed jobs and cron jobs are usually reoccurring (not very accurate with timing) and are started with rake not by a user action, right?
What tool will give me minute accuracy开发者_如何学编程 for this use case?
Twilio Evangelist here.
I like to approach this with Redis backed worker queues. Redis is a key-value store, which we can use with Resque (pronounced 'rescue'), and Resque-Scheduler to provide a queueing mechanism. For example, we can have the application respond to user interaction by creating a call using the Twilio REST API. Then we can queue a worker task that will do something with the call a specified amount of time later. Here, I'm just going to get the status of the call after a few seconds (instead of waiting for the status callback when the call completes).
Heroku have a really good walkthrough on using Resque, there is also an excellent Rails Casts episode on Resque with Rails. A data add-on is available from Heroku called Reddis Cloud to provide a Redis server. Although for development I run a local server on my computer.
I've created a simple app based on the Heroku tutorial and the Rails Casts episode. It has a single controller and a single model. I'm using a callback on the model to create an outbound Twilio call. Such that when a new Call
record is created, we initiate the outbound Twilio call:
class Call < ActiveRecord::Base
# Twilio functionality is in a concern...
include TwilioDialable
after_create do |call|
call.call_sid = initiate_outbound call.to,
call.from,
"http://example.com/controller/action"
call.save
call
end
end
I'm using a concern to initiate the call, as I may want to do that from many different places in my app:
module TwilioDialable
extend ActiveSupport::Concern
include Twilio::REST
def initiate_outbound to, from, url
client = Twilio::REST::Client.new ENV['TW_SID'], ENV['TW_TOKEN']
client.account.calls.create(to: to, from: from, url: url).sid
end
end
This simply creates the outbound Twilio call, and returns the call SID so I can update my model.
Now that the call has been placed, so I want to check on its status. But as we want the call to ring a little first, we'll check it in 15 seconds. In my controller I use the Resque.enqueue_in
method from Resque-Scheduler to manage the timing for me:
Resque.enqueue_in(15.seconds, MessageWorker, :call => @call.id)
This is instructing Resque to wait 15 seconds before performing the task. It is expecting to call a Resque worker class called MessageWorker
, and will pass a hash with the parameters: {:call => @call.id}
. To make sure this happens on time, I set the RESQUE_SCHEDULER_INTERVAL
to 0.1 seconds, so it will be very precise. The MessageWorker
itself is fairly simple, it finds the call record and uses the Call SID to get the updated status and save this to the database:
class MessageWorker
@queue = :message_queue
def self.perform params
# Get the call ID to do some work with...
call = Call.find(params["call"])
# Setup a Twilio Client Helper with credentials form the Environment...
client = Twilio::REST::Client.new ENV['TW_SID'], ENV['TW_TOKEN']
# We could get some
status = client.account.calls.get(call.call_sid).status
# Update my call object.
call.status = status
end
end
When I ran this locally, I had to start the Redis server, the Redis Worker rake task, the Redis Schedule rake task, and I am using Foreman and Unicorn to run the Rails app. You can configure all of this into your Procfile for running on Heroku. The tutorial on Heroku is a great walkthrough for setting this up.
But now I can create a call and have it dial out to a phone. In the mean time I can refresh the calls/show/:id
page and see the value magically updated when the worker process is run 15 seconds later.
I also find that resque-web
is really useful for debugging Resque, as it makes it really easy to see what is happening with your tasks.
Hope this helps!
精彩评论