sidegeeks
sidegeeks

Reputation: 1041

Run Ruby Task Whenever Amazon SQS Queue Is Updated

I've been doing a lot of Sinatra lately and I thought it was time to take it to the next level. Any help would be gladly appreciated guys. So here is what I'm thinking of doing:

App A throws an event to Amazon SQS queue whenever user makes an event. App B does a task (say emails user with a "Hey" message) whenever any event is thrown into the queue. I've never really worked with Cron Jobs other that the below code:

$sum = 1

Thread.new do # trivial example work thread
  while true do
     sleep 3
     $sum += 1
  end
end


get '/' do
    "Testing background work thread: sum is #{$sum}"
end

Thanks Mark Watson for this (http://markwatson.com/blog/2011-11/ruby-sinatra-web-apps-with-background-work-threads.html)

Here are my doubts:

Upvotes: 1

Views: 836

Answers (2)

Pablo Cantero
Pablo Cantero

Reputation: 6357

I would recommend you to have a look at Shoryuken, it's on top of the AWS SDK. And you can easily integrate with Sinatra or any other Ruby app.

get '/' do
  MyWorker.perform_async(msg)
end

Upvotes: 1

Oto Brglez
Oto Brglez

Reputation: 4193

I would suggest that your split your application into 2 parts. One is regular Sinatra web app and another is some kind of background worker.

Example application

This is simple not-for-production working example that you could use.

Create some common boot.rb file where you put your "initialisation" code in:

require 'bundler/setup'

# Use this to load my '.env' that contains AWS credentials
require 'dotenv'; Dotenv.load

# We are using Amazon Ruby SDK
require 'aws-sdk'

# We configure AWS Ruby SDK
AWS.config(
  access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
  secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY')
)

# We get SQS Web Service
sqs = AWS::SQS.new

QUEUE = sqs.queues[ENV.fetch('AWS_QUEUE_URL')]

Simple Sinatra web app.rb that sends message yo your Amazon SQS if you visit /smoke.

require_relative 'boot'
require 'sinatra'

get '/smoke' do
  message = QUEUE.send_message({email: "[email protected]", at: DateTime.now}.to_json.to_s)
  "Message was sent to Amazon SQS with id #{message.id}.\n"
end

Create another file - name it worker.rb - that will subscribe to your Amazon SQS queue and pull messages.

require_relative 'boot'

QUEUE.poll do |msg|
  object = JSON.load(msg.body) rescue {}
  puts "Got your email #{object['email']} at #{object['at']}."
end

My local .env file contains credentials and URL to SQA queue.

AWS_ACCESS_KEY_ID=secret
AWS_SECRET_ACCESS_KEY=secret
AWS_QUEUE_URL=https://sqs.us-west-1.amazonaws.com/...

Running it

Then you simply startup your Sinatra app and worker like so

ruby app.rb # in one terminal
ruby worker.rb # in another terminal

If you then visit /smoke you will see something like this - meaning that job was scheduled.

Message was sent to Amazon SQS with id 788e5e28-8055-4c8f-bb51-c634c327a021.

And in your worker terminal you'll see

Got your email [email protected] at 2014-08-29T15:20:38+02:00.

Now, you don't have to limit yourself to just one worker... You can have as many as you like, one message will be processed only on one worker by default. Another note here is that we are sending JSON as message thats why I've used JSON.load in worker. Amazon SQS sends/receives plain text messages.

Upvotes: 2

Related Questions