Shoryuken và SQS

Giải pháp Sidekiq

Rails có nhiều giải pháp cho background job. Một trong số là Sidekiq.

Sidekis có thể giải quyết hầu hết các vấn đề mà lập trình viên mắc phải. Nó đặc biệt có tác dụng khi phải chịu lượng lớn truy cập từ Rails. Tuy nhiên Sidekiq cũng có một số hạn chế như sau:

  • Nếu bạn không phải là một Pro user ($750 một năm) thì khi process của bạn bị crash, bạn sẽ mất job tương ứng.
  • Nếu phần tải của job tăng lên, bạn sẽ cần một version mạnh hơn của Redis, nó sẽ tốn nhiều tiền và tài nguyên của bạn hơn.
  • Bạn cần phải host dash boarch của nó để quản lý các vấn đề xảy ra với các job.

Giới thiệu Shoryuken

Một cách tiếp cận khác mà bạn có thể sẽ muốn suy nghĩ, đó là sử dụng Shoryuken cho hàng đợi job. Shoryuken làm việc với Amazon SQS (Simple Queue Service). Đây là một nơi lưu trữ cơ bản của các messages mà bạn có thể thực hiện sau thông qua Shoryuken worker. Các worrker sẽ làm việc một cách độc lập với các process chính của Rails. Với SQS à Shoryuken, bạn tạo một queue cho các worker của bạn để sử dụng, và các worker sẽ lần lượt xoay vòng các job cho đến khi hàng đợi trở nên rỗng.

Một vài lợi ích mà bạn có thể thu được khi sử dụng Shoryuken:

  • Nó được build cùng với Amazon SQS, một service cực rẻ (giá chỉ $0.5 trên một triệu Amazon SQS requests)
  • SQS được xây dựng để mở rộng. Bạn có được các lợi thế của các cấu trúc của Amazon giúp việc mở rộng các worker của bạn dễ dàng hơn.
  • Amazon cung cấp một console đơn giản để bạn xem các queue cũng như thiết lập những việc cần làm với các dead messages.
  • Amazon Ruby SDK rất mềm dẻo khi dùng để tạo queue, nó cho phép bạn tạo bao nhiêu queue cũng được.

Trong bài viết này, tôi sẽ hướng dẫn bạn cách thiết lập Shoryuken để sử dụng với Flickr API. Bạn sẽ thấy Shoryuken xử lý các background job với tốc độ rất nhanh.

Tutorial

Thiết lập ban đầu

Để bắt đầu tutorial này, chúng ta sẽ sử dụng Flickr API để tạo ra một thanh tìm kiếm đơn giản, nơi mà ta có thể khởi tạo các bức ảnh dựa trên các id mà ta nhập vào.

  1. Đầu tiên, chúng ta phải thiết lập một tài khoản Yahoo, vì đây là cách duy nhất chúng ta có thể truy cập Flickr API. Khi chúng tôi có tài khoản Yahoo, chỉ cần truy cập trang Tài liệu Flickr
  2. Nhấp vào liên kết Tạo ứng dụng trên trang tài liệu Flickr.
  3. Đăng ký một key phi thương mại tại Flickr.com.
  4. Trên trang tiếp theo, bạn sẽ được yêu cầu nhập một số chi tiết về dự án của bạn. Đơn giản chỉ cần điền vào tên và các bit khác về dự án của bạn.
  5. Bạn sẽ nhận được Key và Secret cho application của bạn. Hãy lưu lại các key này ở một nơi khác, bởi vì chúng ta sẽ cần chúng cho tutorial này.

Rails app

Tiếp theo, tạo một Rails app với một controller action duy nhất. Để tạo mới một Rails app, hãy dùng câu lệnh sau:

rails new shoryuken_flickr

Tiếp theo, tạo một controller. Một controller chuẩn với một index action:

rails g controller Search index

Thêm vào một route cho action này trong config/routes.rb

root 'search#index'

Ở trong index, tạo một search form đơn giản:

<%= form_tag("/", method: "get") do %>
  <%= text_field_tag(:flickr_id) %>
  <%= submit_tag("Search") %>
<% end %>

Chúng ta cần thiết lập một Flickr module để trả về các ảnh của user ID đã submit:

  1. Đầu tiên, ta cài đặt flickr_fu, để có thể dễ dàng lấy được dữ liệu ta cần

  2. Tạo file flickr.yml với các khoá cần thiết. File này để ở trong folder config và nó sẽ có dạng như sau:

    key: <%= ENV["flickrkey"] %>
    secret: <%= ENV["flickrsecret"] %>
    token_cache: "token_cache.yml
    
  3. Bây giờ tao tạo một helper method để trả về các ảnh cho trang index. Trong app/helpers/search_helper.rb, add phần sau đây:

    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
    

Method này trả về các bức ảnh của Flickr user ID mà ta đã cung cấp. Trong app/controllers/search_controller.rb, ta cần đặt vào đó một xử lý để lấy dữ liệu:

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

Bây giờ, chỉ cần tạo một partial nhỏ để khởi tạo bức ảnh. Trong app/views/search tạo một file photo.html.erb như sau:

<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 hiện trên hồ sơ người dùng trong URL. ID ví dụ là [email protected] và nếu bạn gửi giá trị đó trong form, một tập ảnh sẽ được trả lại.

Bây giờ chúng ta có một ứng dụng đang hoạt động có ảnh mới từ Flickr. Điều này là tuyệt vời, nhưng nó rất chậm cho người sử dụng và nó làm mới toàn bộ trang mỗi lần.

Tôi nghĩ rằng ứng dụng này sẽ có thể tốt hơn với một chút với AJAX. Đầu tiên, tạo ra một view index.js.erb trong app/views/search và đưa vào một số Javascript đơn giản:

$('ul').remove();
$('#flickr').append("<%= j render 'photos'%>").html_safe();

Trong controller, ta thêm vào block respond_to:

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

Cuối cùng, trong search form, thêm đặt remote bằng true:

<br/>
  <%= form_tag("/", method: "get", :remote => true) do %>
  <%= text_field_tag(:flickr_id) %>
  <%= submit_tag("Search") %> <% end %>
<br/>

Như vậy ta đã xong phần đầu tiên, nhưng xử lý vẫn đang chỉ là một thread.

Thiết lập Shoryuken

Nếu bạn chưa có tài khoản Amazon Web Services (AWS), bạn sẽ cần phải thiết lập một tài khoản. Hãy làm theo các bước sau đây

  1. Chọn vào "My Account" dropdown menu và chọn "AWS Management Console"
  2. Đăng nhập và sau đó bạn sẽ được đưa đến Console Quản lý AWS.
  3. Ở phía trên cùng bên phải, nhấp vào tên người dùng của bạn trong thanh trình đơn và sau đó nhấp vào "Security credentials".
  4. Bây giờ, bạn sẽ được đưa đến trang nơi bạn có thể truy cập vào AWS Access Key của mình (Access Key ID and Secret Access Key)
  5. Nhấp vào " Create New Access Key" và lấy Acess Key ID và Secret Access Key của bạn. Bạn cần những điều này để chạy Shoryuken và SQS.

Một khi chúng ta có các khóa truy cập AWS, bước tiếp theo là cài đặt và cấu hình các gem liên quan. Trước tiên, cài đặt AWS SDK với các chi tiết có liên quan bằng cách thêm vào Gemfile như sau đây:

gem 'aws-sdk', '~> 2'

Sau đó chạy, bundle install

Chúng ta cần thiết lập AWS SDK với các khoá cần thiết. Tôi thường tạo một file tên là aws.rb và cho vào trong foler config/initializes

touch config/initializers/aws.rb

Thêm file code sau:

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'})

Hãy chắc rằng bạn đã thay thế các key trong file bằng key của bạn.

References

  1. https://www.sitepoint.com/quickly-process-api-requests-with-shoryuken-and-sqs/
  2. https://github.com/phstc/shoryuken