Статьи

Быстро обрабатывать запросы API с помощью Shoryuken и SQS

У Rails есть много решений для фоновых заданий. Одним из них является блестящий Gem под названием Sidekiq, о котором мы писали ранее на Sitepoint .

Sidekiq великолепен и может удовлетворить большинство потребностей разработчиков. Это особенно полезно, так как берет на себя тяжелый подъем от Rails. Тем не менее, у него есть несколько недостатков:

  • Если вы не являетесь профессиональным пользователем (750 долларов в год), и ваш процесс падает, вы потеряете работу.
  • Если ваша рабочая нагрузка увеличивается, вам потребуется более мощная версия Redis, которая стоит больше денег и ресурсов.
  • Вам необходимо разместить его панель мониторинга, чтобы отслеживать, что происходит с вашей работой.

Другим подходом, который вы можете рассмотреть для обработки заданий в очереди, является Shoryuken , который работает в сочетании с Amazon SQS (Simple Queue Service). Это базовое хранилище сообщений, которое вы можете обработать позже с помощью работников Shoryuken. Эти рабочие затем работают вне основных процессов Rails. С помощью SQS и Shoryuken вы создаете очередь для использования вашими работниками, и эти работники циклически выполняют задания, пока очередь не опустеет.

Несколько преимуществ использования Shoryuken:

  • Он построен с учетом Amazon SQS, что невероятно дешево ($ 0,50 за 1 миллион запросов Amazon SQS).
  • SQS построен в масштабе. Вы пользуетесь преимуществами удивительной инфраструктуры Amazon, поэтому ваших сотрудников легко масштабировать.
  • Amazon предоставляет простую консоль для просмотра ваших очередей, а также для настройки того, что происходит с мертвыми сообщениями.
  • Ruby SDK от Amazon очень гибок в создании очередей. Вы можете создать столько, сколько хотите.

В этой статье я расскажу вам, как настроить Shoryuken для использования с Flickr API. Вы увидите, как Шорюкен обрабатывает задания в фоновом режиме со скоростью освещения.

Чтобы начать этот урок, мы собираемся использовать API Flickr, чтобы создать простую панель поиска, где мы можем генерировать фотографии на основе любого введенного идентификатора.

  1. Прежде всего, нам нужно настроить учетную запись Yahoo , так как это единственный способ получить доступ к Flickr API. Если у нас есть аккаунт Yahoo, просто зайдите на страницу Flickr Docs
  2. Нажмите на ссылку « Создать приложение» на странице документов Flickr .
  3. Подать заявку на некоммерческий ключ на Flickr.com .
  4. На следующей странице вам будет предложено ввести некоторые сведения о вашем проекте. Просто введите имя и другие сведения о вашем проекте.
  5. Вы получите ключ и секрет для своего заявления. Запишите их куда-нибудь, потому что они понадобятся нам для этого урока.

Затем настройте приложение Rails с помощью одного действия контроллера. Чтобы настроить новое приложение Rails, сгенерируйте его из командной строки:

rails new shoryuken_flickr

Далее настройте контроллер. Стандартное действие контроллера с index

 rails g controller Search index

Добавьте корневой маршрут к этому действию в config / rout.rb :

 root  'search#index'

На странице указателя настройте простую форму поиска:

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

Мы должны настроить модуль Flickr для возврата фотографий отправляемого идентификатора пользователя:

  1. Сначала мы устанавливаем flickr_fu, который позволяет легко получать нужные данные.
  2. Настройте файл flickr.yml с нашими соответствующими учетными данными. Этот файл находится в папке config и выглядит так:

     key: <%= ENV["flickrkey"] %>
    secret: <%= ENV["flickrsecret"] %>
    token_cache: "token_cache.yml
    
  3. Теперь мы создаем вспомогательный метод для возврата фотографий для страницы индекса. В 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
    

Этот метод возвращает фотографии на основе предоставленного идентификатора пользователя Flickr. В 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 присутствуют в профилях пользователей в URL. Пример ID: 138578671@N04

Теперь у нас есть работающее приложение, которое получает новые фотографии с Flickr. Это потрясающе, но очень медленно для пользователя и каждый раз обновляет всю страницу.

Я думаю, что это приложение будет лучше с небольшим количеством AJAX. Во-первых, создайте представление index.js.erb в app / views / search и вставьте в него простой Javascript:

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

В контроллере убедитесь, что у нас есть блок 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

Наконец, в форме поиска установите для remotetrue

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

Хорошо, это круто, но мы все еще не использовали Shoryuken. Процесс все еще однопоточный.

Настройка Шорюкена

Если у вас еще нет учетной записи Amazon Web Services (AWS) , вам необходимо ее настроить. следить

  1. Нажмите на раскрывающееся меню «Моя учетная запись», а затем нажмите «Консоль управления AWS».
  2. Войдите, и вы попадете на консоль управления AWS.
  3. В правом верхнем углу нажмите свое имя пользователя в строке меню, а затем нажмите «Учетные данные безопасности».
  4. Теперь вы попадете на страницу, где вы можете получить доступ к своим ключам доступа AWS (идентификатор ключа доступа и секретный ключ доступа)
  5. Нажмите «Создать новый ключ доступа» и снимите свой идентификатор ключа доступа и секретный ключ доступа. Это нужно для запуска Shoryuken и SQS.

Когда у нас есть ключи доступа AWS, следующим шагом будет установка и настройка соответствующих гемов. Сначала установите AWS SDK с соответствующими сведениями, добавив в свой Gemfile следующее:

 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.

SQS QUEUE

Наконец, пришло время установить камень Shoryuken. В нашем Gemfile:

 gem 'shoryuken'

Создайте рабочий Shoryuken и некоторое промежуточное программное обеспечение. Я просто создаю новый каталог в приложениях, которые называются работники :

 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

Настройте работника:

 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
        @photos = Photo.find_by_user_id(params[:flickr_id]).photos
      end
      respond_to do |format|
        format.html
        format.js
      end
    end
  end

Теперь мы просто отправляем другое сообщение. На этот раз вы должны увидеть его на консоли SQS. Возможно, вам придется обновить консоль SQS с помощью кнопки обновления, которая находится в правом верхнем углу экрана.

Вы должны увидеть сообщение в своей очереди, но по какой-то причине оно не обрабатывается. Лучше разберись с этим. Откройте другое окно терминала и перейдите к своему проекту. Когда вы там, вы должны выполнить следующую команду:

 bundle exec shoryuken -R -C config/shoryuken.yml

Теперь вы должны увидеть, как ваш работник очищает очередь. Когда вы вернетесь к своему приложению, вы, вероятно, увидите ошибку. Помните, что Shoryuken работает в фоновом режиме, поэтому он не может создавать переменные экземпляра для вашего текущего процесса. Вы можете сохранить фотографии в базе данных, а затем опросить таблицу, когда результаты будут получены.

 rails g model Photo user_id:string photos:string

Теперь мы просто проверим наш файл переноса и убедитесь, что добавляются правильные поля. Откройте файл миграции (в db / migrate ) и убедитесь, что он выглядит следующим образом:

 class CreatePhotos < ActiveRecord::Migration
  def change
    create_table :photos do |t|
      t.string :user_id
      t.string :photos

      t.timestamps null: false
    end
  end
end

Если все выглядит хорошо, нам нужно перенести базу данных.

 rake db:migrate

Убедитесь, что сериализован массив, который возвращается в нашей базе данных. В приложении / models / photos.rb :

 class Photo < ActiveRecord::Base
  serialize :photos
end

Затем обновляйте нашу таблицу каждый раз, когда рабочий запускается. В нижней части SearchHelper#user_photos

 photos = flickr.photos.search(:user_id => id).values_at(0..(5 - 1))
Photo.create(:user_id => id, :photos => [photos])

Чтобы увидеть, как он работает, добавьте задержку к действию контроллера поиска, чтобы дать вашей базе возможность обновиться. В реальном мире я предлагаю более элегантное решение с использованием AJAX.

 sleep 1.5

Там у вас есть это. Теперь вы знаете, как использовать некоторые потрясающие библиотеки для обработки поставленных в очередь задач с помощью Shoryuken. Хотя этот пример очень надуманный, я использовал его, чтобы продемонстрировать, как использовать Shoryuken с SQS. Без сомнения, у вас, вероятно, есть хотя бы один вариант использования, который выиграл бы от сообщений в очереди.