「Rails4でサイトを構築する」シリーズ目次
- Rails環境構築編
- Scaffold利用編
- Bootstrap導入編
- WYSIWYG導入編
- CSV出力機能編
- スクレイピング機能編(nokogiri)
- 非同期処理導入編(delayed_job)
- デプロイ環境構築編(capistrano3)
今回は、delayed_jobを使って非同期処理を行う機能を実装してみたいと思います。
delayed_jobとは
処理に時間が掛かるようなタスクをバックグラウンドで非同期処理を実現するGemです。
同じようなものにResque gemがありますが、
delayed_jobを使っていて困ることはないので、使い慣れたdelayed_jobを使っています。
ファイルをアップロードして内容を解析してデータを保存する処理とかサイトをクローリングしてスクレイピングして情報を保存する処理等、
ブラウザから処理の実行を指示し、そのレスポンスに1分とかかかっているとサービスとして成り立たないので、このような処理に時間を要するものは、
delayed_job等を使い非同期に処理するほうがよさそうです。
delayed_jobのインストール
Gemfile
gem 'delayed_job_active_record'
gem "daemons" #これも入れないとbackground実行できない
上記を追加し、bundle install
を実行
その後、
bundle exec rails g delayed_job:active_record
実行結果
create bin/delayed_job
chmod bin/delayed_job
create db/migrate/20140602023844_create_delayed_jobs.rb
migrationファイルができています。基本的にそのままで大丈夫なので、
bundle exec rake db:migrate
を実行します。
sqlite3だと結果は以下のようになっています。
sqlite>.schema
CREATE TABLE "delayed_jobs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "priority" integer DEFAULT 0 NOT NULL, "attempts" integer DEFAULT 0 NOT NULL, "handler" text NOT NULL, "last_error" text, "run_at" datetime, "locked_at" datetime, "failed_at" datetime, "locked_by" varchar(255), "queue" varchar(255), "created_at" datetime, "updated_at" datetime);
CREATE INDEX "delayed_jobs_priority" ON "delayed_jobs" ("priority", "run_at");
delayed_jobの起動と停止
ここまで行うと、delayed_jobの起動ができます。
delayed_jobの起動
#{プロジェクトディレクトリパス}/bin/delayed_job start
本当に動いたかチェック
ps aux | grep delayed_job
結果
kazuma 14382 0.4 4.5 59640 47052 ? Sl 15:39 0:00 delayed_job
kazuma 14729 0.0 0.0 4404 824 pts/2 S+ 15:39 0:00 grep --color=auto delayed_job
一番上がdelayed_jobのプロセスです。
delayed_jobの停止
スクレイピング処理をdelayed_jobを使って非同期化してみる
スクレイピング機能編(nokogiri)で作ったものを参考に進めて行きます。
スクレイピングした情報を保存をするためにmigrationファイルとmodelファイルを作成します。
※ 一覧とか編集とかのページを作るなら、rails g scaffoldのほうがいいかも
bundle exec rails g model Tag name:string
bundle exec rake db:migrate
controllerを作成
- app/controllers/page_controller.rb
class PageController < ApplicationCtonroller
def do_scrape
Scrape.delay.bps_global_navi #非同期化したいメソッドの前にdelayを追加するだけです。
redirect_to root, notice: '処理を開始しました。'
end
end
config/routes.rb
# 以下をroutes.rbに追加
scope :page do
get 'do_scrape', to: 'page#do_scrape'
end
前回作ったlib/scrape.rbをDB保存するように改修
- lib/scrape.rb
require 'nokogiri'
require 'open-uri'
module Scrape
BPS_SITE_URL = '//www.bpsinc.jp'
BPS_TARGET_CSS = '.footer-container ul.site-map-child li a' # サイト変わってた。。。ので修正
def self.bps_global_navi
doc = Nokogiri::HTML(open(BPS_SITE_URL))
doc.css(BPS_TARGET_CSS).each do |link|
Tag.find_or_create_by(name: link.content)
end
end
end
後は、/page/do_scrapeをたたくだけです。
delayed_jobの起動は忘れずに。
delayed_jobあるある
Q. 修正したコードが反映されません!
A. delayed_jobを再起動しましょう。
Q. 既存のサイトにアップロードしたテキストファイルをパースする部分を非同期化したらエラーになりました。
A. アップロードしたファイルはいったんどこかに保存するようにして、非同期化部分でそのファイルを読み込んでパースするように修正しましょう。