下林明正のブログ

個人的かつ雑多なブログです。

EventMachineでジョブキューを高速に処理するたたき台2

昨日の続き。

この書き方ならパフォーマンスにも問題無さそうだしネストしたタスクも綺麗に書けて良さそう。

require 'rubygems'
require 'eventmachine'

MAX_RETRY_COUNT = 3
CONCURRENCY = 2

class Mailer < EM::DefaultDeferrable
  def initialize(mail_address)
    @mail_address = mail_address

    callback {
      puts "#{@mail_address}: sent"
    }
    errback {
      puts "#{@mail_address}: failed"
    }
  end

  def send
    puts "#{@mail_address}: sending..."
    rand >= 0.5 ? succeed : fail
  end
end

jobs = (1..5).to_a
running = false
retry_count = 0

EM.run {
  EM.add_periodic_timer(1) {
    break if running

    puts "retry (#{retry_count}/#{MAX_RETRY_COUNT})" if retry_count > 0
    EM::Iterator.new(jobs.clone, CONCURRENCY).each( proc{|i, iter|
      mailer = Mailer.new("hoge_#{i}@example.com")
      mailer.callback {
        mailer2 = Mailer.new("fuga_#{i}@example.com")
        mailer2.callback {
          jobs.delete(i)
          iter.next
        }
        mailer2.errback {
          iter.next
        }
        mailer2.send
      }
      mailer.errback {
        iter.next
      }
      mailer.send
    }, proc{
      if jobs.length > 0 and retry_count < MAX_RETRY_COUNT
        retry_count += 1
        running = false
      else
        puts 'done!'
        EM.stop
      end
    })
    running = true
  }
}