- 原文链接: 利用 Shoryuken and SQS 快速处理 API 请求
- 译文出自: 掘金翻译计划
- 译者: circlelove
- 校对者: rccoder, MAYDAY1993

Rails 为后台工作提供了相当多的解决方案。其中一个就是被称为 Sidkiq 的智能 Gem, 我们之前在 Sitepoint 上提到过。
Sidekiq 相当棒,能解决大多数开发中的问题。尤其是 Rails 繁重问题上相当有用。然而,它也有一些不足。
- 如果你不是专业版用户(每年支付750美元),而你的进程崩溃的话,将会丢失你的工作
- 如果你的工作量增加,你需要更强大版本的 Redis ,而它耗费更多的成本和资源。
- 为了监控你工作上发生的一切,你需要把握它的控制面板。
想要解决排队任务的你需要考虑的另一种方法是 Shoryuken ,它和亚马逊的 SQS (Simple Queue Service)协同工作。这是一个基本消息存储,之后你可以通过 Shoryukeσn workers 进行处理。这些 workers 之后在主 Rails 进程外部工作。有了 SQS 和 Shoryuken,你可以为 workers 创建队列利用 workers 循环任务直到队列空闲。
使用 Shoryuken 有以下好处:
- 他是以 Amazon SQS 构建的,难以置信的便宜(每一百万次 Amazon SQS Requests 只要0.5美元)。
- SQS 是用来规模化作业的。利用亚马逊这个令人惊喜的基础配置,你可以轻松地简化你的 workers 。
- 亚马逊提供了一个简单的控制台来查看队列以及配置死消息的情况。
- 亚马逊的 Ruby SDK 在创建队列的时候十分灵活。如果你愿意可以创建很多队列。
本文档中,我会带你来配置带有 Flickr API 的 Shoryuken 。你将见证 Shoryuken 如何在后台光速处理任务。
为了开始这个教程,我们将用 Flickr API 来创建一个简单的搜索框,这样就可以根据 id 输入来生成照片。
首先,我们需要设置雅虎账户,因为这是我们可以访问 Flickr API 唯一的方式。配好雅虎账户之后,简单地查看一下Flickr 文档页面。
在 Flickr.com 申请一个非商业密钥。
下一个页面当中,你会被要求输入项目的具体信息,简单地填入项目名称和事项等即可。
你会收到应用的密钥和密码。把他们写在某个地方,因为这个教程当中需要用到。
接下来,搭建一个单控制器行为的 Rails app 。要生成新的 Rails app,利用如下命令行生成:
rails new shoryuken_flickr
下一步,配置控制器。带有index行为的控制器行为是完美的:
rails g controller Search index
在config/routes.rb 里添加一个根路径到这个操作上:
root 'search#index'
在索引页,设置一个简单的搜索框:
<%= form_tag("/", method: "get") do %>
<%= text_field_tag(:flickr_id) %>
<%= submit_tag("Search") %>
<% end %>
我们必须配置 Flickr 模块来返回用户提交 id 的照片:
- 首先,我们得安装[ flickr_fu ] (github.com/commonthrea…),这样更容易抓取我们需要的数据。
利用相关凭证配置 flickr.yml 文件。这个文件在 config 文件夹里作业,看起来是这样的:
key: <%= ENV["flickr<em>key"] %> secret: <%= ENV["flickr</em>secret"] %> token_cache: "token_cache.yml现在我们可以为目录页创建一个 helper 方法来返回照片。在 app/helpers/search_helper.rb 添加如下内容:
module SearchHelper def user_photos(user_id, photo_count = 5) flickr = Flickr.new(File.join(Rails.root, 'config','flickr.yml')) flickr.photos.search(:user_id => user_id).values_at(0..(photo_count - 1)) end end
基于提供的用户 id 这种方法可以返回照片。在 app/controllers/search_controller.rb ,需要一个操作来抓取数据:
class SearchController < ApplicationController
def index
if params[:flickr_id]
@photos = user_photos(params[:flickr_id],10).in_groups_of(2)
@id = params[:flickr_id]
end
end
end
现在,只要创建一个小的片段来生成照片。在 app/views/search 里通过如下代码添加一个 photos.html.erb 文件:
<ul>
<% @photos.each do |photo| %>
<li> <% photo.each do |p| %>
<%= link_to(image_tag(p.url(:square), :title => p.title, :border => 0, :size => '375x375'), p.url_photopage) %>
</li>
<% end %>
<% end %>
</ul>
Flickr id 就呈现在 URL 的用户配置里。以 138578671@N04 这个 ID 为例,如果你在表单里提交了有效值,就会返回一系列照片。
现在我们有了一个从 Flickr 获取新照片的应用。这很棒,但是对用户来说这还很慢,而且每次搜需要刷新整个页面。
我认为加上一点 AJAX 这个应用会更完善,在 app/views/search 创建 index.js.erb 视图,并添加一些 Javascript 的内容:
$('ul').remove();
$('#flickr').append("<%= j render 'photos'%>").html_safe();
控制器当中,要保证我们对代码阻塞有 响应
class SearchController < ApplicationController
def index
if params[:flickr_id]
@photos = user_photos(params[:flickr_id],10).in_groups_of(2)
@id = params[:flickr_id]
end
respond_to |format|
format.html
format.js
end
end
end
最后,每个搜索表单中,设置 remote 为 ture:
<br/>
<%= form_tag("/", method: "get", :remote => true) do %>
<%= text_field_tag(:flickr_id) %>
<%= submit_tag("Search") %> <% end %>
<br/>
好,这很酷,但是我们还没有用到 Shroyuken 。进程还是单线程的。
配置 Shoryuken
如果你还没有 Amazon Web Services (AWS) 账户,你需要创建一个。按照:
- 点击“我的账户”下拉菜单,然后单击“AWS 控制台”。
- 登录之后就进入了控制台。
- 在右上方,单击菜单栏中的用户名,然后单击“安全验证”。
- 现在你被带到一个页面里,你可以获取访问密钥的 id 和密码。
- 点击“创建新的访问密钥”得到你的访问密钥 ID 和密码。你需要这些来运行 Shoryuken 和 SQS。
这样我们有了 AWS 的访问密钥,下一步就是安装和配置相关的 gem 。添加如下代码到你的 Gemfile里来安装带有相关细节的 AWS SDK 。
gem 'aws-sdk', '~> 2'
之后,bundle install。
我们需要利用相关证书配置 AWS SDK。完成通常创建一个叫aws.rb 的文件,放在 config/initializers 文件夹里面。
touch config/initializers/aws.rb
在文件中添加以下代码:
Aws.config.update({
region: "eu-west-1",
credentials: Aws::Credentials.new(your_access_key, your_secret_key)
})
sqs = Aws::SQS::Client.new(
region: "eu-west-1",
credentials: Aws::Credentials.new(your_access_key, your_secret_key)
)
sqs.create_queue({queue_name: 'default'})
确保用你的实际证书替代原证书
如果我们查看 SQS 控制台,会发现重启 Rails 服务器之后会出现新的队列。

最后,到了安装 Shoryuken gem 的时候了。在我们的 Gemfile 里:
gem 'shoryuken'
创建 Shoryuken worker 和其他中间件。我只是创建了在 apps 下创建了一个新的名叫 workers 的目录:
mkdir app/workers
touch app/workers/flickr_worker.rb
touch app/workers/flickr_middleware.rb
touch config/shoryuken.yml
配置 Flickr 中间件:
class FlickrMiddleware
def call(worker_instance, queue, sqs_msg, body)
puts 'Before work'
yield
puts 'After work'
end
end
配置 worker :
class MyWorker
include Shoryuken::Worker
shoryuken_options queue: QUEUE_NAME, auto_delete: true, body_parser: JSON
def perform(sqs_msg, body)
id = body.fetch('id')
flickr = Flickr.new({
key:"your_key",
secret:"your_secret",
token_cache:"token_cache.yml"
})
flickr.photos.search(:user_id => id).values_at(0..(5 - 1))
end
end
同时也需要按如下方式配置我们的 config/shoryuken.yml 文件:
aws:
access_key_id: 'AWS_KEY'
receive_message:
attribute_names:
- ApproximateReceiveCount
- SentTimestamp
region: eu-west-1
secret_access_key: 'AWS Secret Key'
concurrency: 25
delay: 0
queues:
- [default, 6]
完美! 我们差不多配置好了所有的东西准备开始了。只剩下了给队列发送消息了。在搜索控制器上,写入如下代码:
“`
class SearchController < ApplicationController
include SearchHelper
def index
# 138578671@N04 submit this in the form
if params[:flickr_id]
FlickrWorker.perform_async("id" => params[:flickr_id])
sleep 0.1