【Rails】Active JobとWheneverでスクレイピングを自動化(#2 Active Jobの設定方法)

プログラミング初心者の勉強ブログ #67

RailsのActive Jobとwheneverを使って、スクレイピングを自動化させてみようと思います。「スクレイピングを実行後、その内容をデータベースに保存する」Jobをコーディングし、Job管理テーブルにそのJobを登録する流れを解説します。今回はActive Jobの設定方法とコーディングです。

 

目次

[toc]

 

前回までの内容

前回はActive Jobの仕組みと処理の流れを確認しました。

[blogcard url=”https://whatsupguys.net/programming-school-dive-into-code-learning-65/”]

Active Jobの流れ

今回はバックグラウンドの非同期処理について、Gemの「Delayed Job」を使い、Active Jobの設定とコーディングを行います。

 

Active Job設定手順

Active Jobを実装したいRailsアプリケーションを、すでに作成している段階からの解説になります。

 

具体的には、

// ターミナルに入力
$ rails new YOUR_APP -d postgresql
$ rails g scaffold YOUR_MODEL_NAME
$ rails db:create db:migrate

この3つが完了し、DBが作成されている状態です。

 

※データベースは「postgresql」を使用しております。

※Rails 5.1.1を使用しております。

※YOUR_APPとYOUR_MODEL_NAMEは、自分のアプリ名とモデル名です。

※Macなのでターミナルにて実装しております。

 

Delayed Jobのインストール

Gemfile

// Delayed Jobをインストール
gem 'delayed_job_active_record'

 

Gemfileに上記コードを記入後、「$ bundle install」を行います。

 

Active Jobのアダプター設定

インストールした「Delayed Job」を、Active Jobで使用するためにアダプター設定を行います。「config/application.rb」を開き、「config.active_job.queue_adapter = :delayed_job」を追加します。

 

config/application.rb

require_relative 'boot'

require 'rails/all'

Bundler.require(*Rails.groups)

module UranaiApp
  class Application < Rails::Application
    config.load_defaults 5.1
    config.time_zone = 'Asia/Tokyo'
    config.active_record.default_timezone = :local
    
    # ↓追加
    config.active_job.queue_adapter = :delayed_job
  end
end

 

これを行うことで、「Delayed Job使うよ」とActive Jobに伝えることができます。

 

Job管理テーブルの作成

次は「タスク管理表」である、Job管理テーブルを作成します。

 

// ターミナルで入力
$ rails g delayed_job:active_record

 

実行すると、「bin/delayed_job」ファイルとマイグレーションファイルがcreateされます。

コマンド入力後ターミナル画面

 

ちなみにそれぞれの中身は以下の通りです。

 

bin/delayed_job

#!/usr/bin/env ruby

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
require 'delayed/command'
Delayed::Command.new(ARGV).daemonize

 

db/migrate/20181107005419_create_delayed_jobs.rb(マイグレーションファイル)

class CreateDelayedJobs < ActiveRecord::Migration[5.1]
  def self.up
    create_table :delayed_jobs, force: true do |table|
      table.integer :priority, default: 0, null: false # Allows some jobs to jump to the front of the queue
      table.integer :attempts, default: 0, null: false # Provides for retries, but still fail eventually.
      table.text :handler,                 null: false # YAML-encoded string of the object that will do work
      table.text :last_error                           # reason for last failure (See Note below)
      table.datetime :run_at                           # When to run. Could be Time.zone.now for immediately, or sometime in the future.
      table.datetime :locked_at                        # Set when a client is working on this object
      table.datetime :failed_at                        # Set when all retries have failed (actually, by default, the record is deleted instead)
      table.string :locked_by                          # Who is working on this object (if locked)
      table.string :queue                              # The name of the queue this job is in
      table.timestamps null: true
    end

    add_index :delayed_jobs, [:priority, :run_at], name: "delayed_jobs_priority"
  end

  def self.down
    drop_table :delayed_jobs
  end
end

 

「Job管理テーブル」の元となるマイグレーションファイルが生成されているので、migrateしてテーブルを作成します。

// ターミナルに入力
$ rails db:migrate

 

Job設定ファイルの作成

Job管理テーブルを作成したら、「業務マニュアル」であるJob設定ファイルを作成します。

 

// ターミナルに入力
$ rails g job YOUR_JOB_NAME

 

実行すると、

実行後ターミナル画面

 

jobs/ YOUR_JOB_NAME.rbファイルが作成されます。

 

app/jobs/fortune_scraping_job.rb

class FortuneScrapingJob < ApplicationJob
  queue_as :default

  def perform(*args)
    # Do something later
  end
end

 

このようなファイルが作成され、「app/jobs/fortune_scraping_job.rb」の 「# Do something later」の箇所に、Jobの内容をコーディングすることでJob設定ができます。

 

class FortuneScrapingJob < ApplicationJob
  queue_as :default

  def perform
    require 'faraday'
    require 'kconv'

    # 星座占いまとめ
    signs = ["おひつじ座", "おうし座", "ふたご座", "かに座", "しし座", "おとめ座", "てんびん座", "さそり座", "いて座", "やぎ座", "みずがめ座", "うお座"]
    signs.each do |sign|
      Mezamashi.mezamashiFortune(sign)
      Gudetama.gudetamaFortune(sign)
      Gogo.gogoFortune(sign)
    end

    # 誕生月占い
    for month in 1..12 do
      Sukkirisu.sukkirisuFortune(month)
    end

    # ゴーゴー星占い総合
    Gogototal.gogoFortuneTotal
  end
end

 

Jobを入れ込みます。ちなみに、今回僕は「朝の情報番組の占い結果を公式サイトからスクレイピングし、データベースに保存する」内容のJobを設定しました。「Mezamashi」「Gudetama」「Gogo」「Sukkirisu」モデルに、それぞれスクレイピング用のメソッドを書き込んで、「Mezamashi.mezamashiFortune(sign)」の形で引っ張ってきております。

 

※スクレイピングのメソッドについては、

[blogcard url=”https://whatsupguys.net/programming-school-dive-into-code-learning-64/”]

ここに書いてます。良かったら見てください。

 

Jobのエンキューのタイミングを設定

各種設定とコーディングが終わったら、あとは設定したJobをエンキューするタイミングを設定します。

「FortuneScrapingJob」クラスに対し、「perform_later(引数)」メソッドを当ててやると、設定したJobがJob管理テーブルにエンキューされます。引数はあってもなくても大丈夫です。

 

例えば、「app/controllers/fortune_controller.rb」ファイルのindexアクションに、

 

app/controllers/fortune_controller.rb

class FortunesController < ApplicationController

  def index
    FortuneScrapingJob.perform_later
  end

end

 

Jobのクラスを入れておくと、indexアクションが起動したタイミング(index.html.erbのリクエストが来たとき)で、Jobが実行されます。「perform_later」は、すぐにJobを実行するメソッドです。

 

「FortuneScrapingJob.perform_later」を、実行したいタイミングのメソッド内に入れることで、メール送信ボタンクリック時などに、Jobのエンキュータイミングを合わせられます。

 

また、時間差も可能です。その場合は「perform_later」の手前に、「set()」メソッドを付け加えます。具体的には、

「FortuneScrapingJob.set(wait_until: Date.tomorrow.noon).perform_later(引数)」

とすると、「クリックされたタイミングから数えて、翌日の正午に実行」になります。

 

次回の内容では、この「FortuneScrapingJob.perform_later」を、Wheneverというcrontabの設定が行えるgemを使い、毎朝自動でJobが実行され占い結果のスクレイピングが行われるよう、設定をかけます。

 

ワーカーの起動

Jobがエンキューされたら、次はワーカーの出番です。Active Jobで処理を完了するにはワーカーが不可欠です。開発環境では、「$ rails s」でローカルサーバーを起動するのと同様に、自分でワーカーを起動しなければなりません。

そのため、ターミナルを2つ使う必要があります。「ワーカー用のターミナル」と「サーバー用のターミナル」です。

 

新規タブもしくはウィンドウで新しくターミナルを開き、カレントディレクトリをJobを設定したRailsアプリのディレクトリに合わせ、

// ターミナルに入力
$ rails jobs:work

コマンドを入力します。これでワーカーが起動しました。ワーカー用ターミナルに「Starting job worker」と表示されて入れば起動してます。

 

以上の手順で行うと、開発環境でActive Jobが稼働します。ワーカーが起動した状態で、実際に設定したJobを管理テーブルにエンキューしてみてください。コードに問題がなければ、ワーカーがJobを見つけ次第実行され、処理が完了するはずです。

Actie Jobの流れ

 

まとめ

今回はActive Jobの設定とコーディングまでです。次回はJobエンキュータイミングを毎朝自動更新にするために、wheneverを利用してcrontab設定を行います。これが完了することで、無事バッジ処理の機構が完成します。

以上ありがとうございました。

 

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA