LoginSignup
10
11

More than 5 years have passed since last update.

Deleyed Jobのソースコードを読む

Last updated at Posted at 2015-11-08

概要

Rubyで非同期処理を行うためのgemのdelayed_jobのソースコードを読む中で学んだことをまとめていきます(週1回ずつ更新予定)。
https://github.com/collectiveidea/delayed_job

delayed_jobについて

  • delayed jobについて

以下のQiitaの記事が凄くわかりやすいです。
http://qiita.com/azusanakano/items/1d2629763f35b5466286

  • capistranoでのdelayed jobの設定

デプロイするときの設定。
https://github.com/collectiveidea/delayed_job/wiki/Delayed-Job-tasks-for-Capistrano-3

内容

第1回: SignalとThread

ソースコード

DelayedJobは、アプリケーションと別のプロセスを走らせて、そのプロセスが一部の処理を担当することで、非同期処理を実現する。そのプロセスを走らせるコマンドが以下。

rake jobs:work

第1回はここから順にコードを読んでいくことに。

このrakeタスクは以下に実装されている。
https://github.com/collectiveidea/delayed_job/blob/master/lib/delayed/tasks.rb#L7-L10

namespace :jobs do
  desc 'Start a delayed_job worker.'
  task :work => :environment_options do
    Delayed::Worker.new(@worker_options).start
  end

Workerクラスがプロセスの起動を担っているとわかる。Workerクラスのstartメソッドは以下に実装されている。
https://github.com/collectiveidea/delayed_job/blob/master/lib/delayed/worker.rb#L150-L190

module Delayed
  class Worker

    def start # rubocop:disable CyclomaticComplexity, PerceivedComplexity
      trap('TERM') do
        Thread.new { say 'Exiting...' }
        stop
        raise SignalException, 'TERM' if self.class.raise_signal_exceptions
      end
      # ...
    end

  end
end

いきなり'trap'とか'Thread'とか出てきて何も分からなかったので、まずはこの辺のことをググって勉強。

Signalクラス

まず最初の'tarp'は、'Signal'クラスのメソッド。

シグナルは、例えばプログラムの実行中にCtrl-Cを押すとプログラムを強制終了することができますが、そういったプログラムとは別の外部からの入力(この例だとCtrl-C)を受け付ける。

Signalクラスを使ったサンプルコード。

While true
  puts 'Chris'
  sleep(2) # 2秒ごとに'Chris'と表示される
  Signal.trap(:INT){
    puts "Stop" # Ctrl-Cを押すと'Stop'と表示される
    exit
  }
end

これを実行すると、

Chris # 無限ループでChrisと表示される
Chris
...
Chris # ここでCtrl-Cを押す
Stop # プログラムが終了する

こんな挙動になる。delayed_jobでworkerを動かしているときもCtrl-Cでプロセスを終了できるが、これはこういった具合に実装されている。

Threadクラス

次にThreadクラスのインスタンスを生成している。スレッドはメモリを共有するが、実行を並列化するための仕組み。

以下サンプルコード。

def thread_sample
  threads = []
  3.times do |i|
    threads << Thread.new do
      sleep(3-i)
      puts "#{i+1}番目の処理"
    end
  end
end

やっていることとしては、1回目の処理は3秒経ってから実行され、2回目の処理は2秒経ってから実行され、3回目の処理は1秒経ってから実行されるというもの。実行結果は以下。

3番目の処理
2番目の処理
1番目の処理

非同期に実行されていることが分かると思います。
この辺の非同期な実行の部分にdelayed_jobの実装の本質があるのかなと思ったところで第1回は終了です。

分かったことまとめ

  • delayed_jobのプロセスはWorkerクラスに実装されている
  • Signalクラスを使って、workerを終了させられる
  • Threadクラスによって並列処理を行っている(かも) > 次回以降

参考にしたページ

シグナル
http://docs.ruby-lang.org/ja/2.0.0/class/Signal.html
http://www.oki-osk.jp/esc/linux/signal.html
http://dark7110.blog.fc2.com/blog-entry-17.html
http://unageanu.hatenablog.com/entry/20080127/1201423758

スレッド
http://docs.ruby-lang.org/ja/2.1.0/class/Thread.html
http://shirusu-ni-tarazu.hatenablog.jp/entry/2013/07/02/042448
https://recompile.net/posts/active_record_in_a_multi-threaded.html

第2回

To Be Continued...

10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11