Upgrade to Pro — share decks privately, control downloads, hide ads and more …

デプロイで止まらないバッチ処理を求めて

 デプロイで止まらないバッチ処理を求めて

Heroku Meetup #27 で『デプロイで止まらないバッチ処理を求めて』という話をしてきた #herokujp
https://developer.feedforce.jp/entry/2019/12/14/153000

D6c5403c0b6ef2f9fd51910ea38323a3?s=128

Takashi Masuda

December 13, 2019
Tweet

More Decks by Takashi Masuda

Other Decks in Programming

Transcript

  1. デプロイで止まらない
 バッチ処理を求めて
 Heroku Meetup #27 "Heroku Vitamin!"
 2019-12-13 @masutaka


  2. 自己紹介
 • 増田貴士(@masutaka)
 • 株式会社フィードフォース
 • EC Boosterの雑用係
 • 今回説明するバッチ処理もそれなりに面倒を見ている


    • 最近はPromoteを使ったブランチ戦略を考え中
 https://www.feedforce.jp/ 

  3. Heroku Meetup登壇履歴
 • Heroku Meetup #23 "Heroku Dynamite!!"
 ◦ 『先々週

    GA になった heroku.yml を使った Docker Deploy の紹介』 
 • Heroku Meetup #25 "Heroku Ghost"
 ◦ 『デプロイ元をCircleCIからHerokuに乗り換えた話。ヒヤリもあるよ』 
 • Heroku Meetup #27 "Heroku Vitamin!" ← 今日!
 ◦ 『デプロイで止まらないバッチ処理を求めて』 
 https://speakerdeck.com/masutaka 

  4. EC Booster
 国内初のGoogleショッピング広告自動運用ツール
 https://ecbooster.jp/ 


  5. EC Boosterの技術スタック
 Heroku App Web Dyno GraphQL Client (apollo-client) GraphQL

    Server (graphql-ruby on Rails) Worker Dyno Chrome (headless mode) chromedriver sidekiq Heroku Postgres Heroku Redis
  6. 前提


  7. 前提
 • EC Boosterの全てのバッチ処理は冪等性を持たせており、 Dynoが再起動しても問題はない


  8. 課題


  9. 課題
 • とは言え、なんとなく再起動して欲しくないバッチ処理もある。 デプロイのたびに少しドキドキ
 ◦ 例: ChromeがHeadless modeで動作する、書き込みを伴うバッチ処理 
 •

    頻度が少ないバッチ処理のために、割と強いDynoを起動し続 けるコストも課題に感じていた

  10. Dynoの再起動とは


  11. Dynoの再起動とは
 • 稼働中のDynoが破棄され、新しいDynoが起動する
 • ローカルファイルシステムは破棄されることとなる
 https://devcenter.heroku.com/articles/dynos#restarting 


  12. いつ再起動されるか?
 • デプロイした時
 • config vars(環境変数)を変更した時
 • Add-onを変更した時
 • 手動再起動($

    heroku ps:restart)した時
 • 以上が24時間(+ ランダムで216分)行われなかったら
 ◦ Cyclingと呼ばれる
 • その他、必要に応じて
 https://devcenter.heroku.com/articles/dynos#restarting 

  13. 再起動の流れ
 1. DynoにSIGTERMが送られる
 2. アプリケーションは30秒以内(できればもっと早く)に終了する 必要がある
 3. 終了しない場合、DynoにSIGKILLが送られ、強制停止させられ る
 https://devcenter.heroku.com/articles/dynos#shutdown

  14. 今までのEC Boosterのバッチ処理


  15. 今までのEC Boosterのバッチ処理
 • SidekiqがActive Job(Rails)のアダプタとして動作
 • Sidekiqでジョブが起動し、バッチ処理が実行される


  16. Heroku App Web Dyno GraphQL Client (apollo-client) GraphQL Server (graphql-ruby

    on Rails) Worker Dyno Chrome (headless mode) chromedriver sidekiq Heroku Postgres Heroku Redis
  17. デプロイ時の動作
 1. デプロイすると、SidekiqはSIGTERMを受け取る
 2. 実行中のジョブは一旦キュー(Redis)に戻される
 3. 新しいDynoが起動したら、ジョブが再実行される


  18. 今動いているバッチ処理は
 止めないでくれ!


  19. 改善しました!


  20. 現在のEC Boosterのバッチ処理


  21. 現在のEC Boosterのバッチ処理
 • Sidekiqでジョブを動かすところまでは同じ
 • そのジョブはバッチ処理を行わず、バッチ処理を実行する One-Off Dynoを起動する


  22. Heroku Platform APIを使って、One-Off Dynoを作成
 Heroku App Worker Dyno sidekiq One-Off

    Dyno Rails runner 作成 https://devcenter.heroku.com/articles/platform-api-reference 
 • One-Off Dyno上でバッチ処理を行うRails runnerが起動される 
 • バッチ処理が終わると、One-Off Dynoは終了&破棄される 

  23. Rubyでの実装例(platform-api gemを利用)
 dyno = ::PlatformAPI::Dyno.new( ::PlatformAPI.connect('{{Heroku API Key}}'), ) dyno.create(

    '{{Heroku App Name}}', attach: false, # (1) command: %!rails r "SampleCoreJob.perform_now(shop_id: '#{shop.id}', global_executions: #{global_executions})"!, force_no_tty: nil, # (2) size: 'performance-m', type: 'run', time_to_live: 1.hour, ) # (1) false: 標準出力/標準エラー出力をアプリログに流す # (2) "attach: true" の時に意味があるようだ https://rubygems.org/gems/platform-api 

  24. 良かったこと
 • Dynoの寿命を自分でコントロール出来た
 ◦ 最大24時間。もちろん勝手に再起動しない 
 • 同時実行数はあまり気にしなくて良かった
 ◦ Heroku

    App単位で100 Dynoまで同時起動できるとのこと。増やすことも可能らしい 
 • 強いDynoを使っても、ほとんど料金が増えなかった
 ◦ 2019/11は$1.60
 ◦ もちろんバッチ処理の起動時間によります 

  25. 悪かったこと
 • リトライが面倒
 • リトライが面倒
 • リトライが面倒


  26. リトライが面倒だった(図だと簡単に見える...)
 Heroku App Worker Dyno sidekiq One-Off Dyno Rails runner

    作成 リトライ
  27. サンプルコード
 https://git.io/Je9HM


  28. 専用のリトライメソッドを作成した
 • 今まではActive Jobのretry_on等で自身をリトライすればよかった
 • そのままの実装だと、One-Shot Dynoではなくworker Dyno上でリトライ されてしまう
 •

    自身ではなく、自身をキックするジョブをリトライする必要がある
 • 今回はretry_onを改造したretry_oneshot_onというメソッドを作った

  29. 状態を自前で記憶する必要があった
 • 今まではActive Jobがインスタンスを引き継いでくれた
 ◦ 何回目のリトライかも覚えていてくれる(executions)
 • global_executionsという概念をでっち上げ、最初のジョブから丁寧に渡 すようにした
 •

    おかげさまでActive Jobの実装に詳しくなれた

  30. 今後の展望
 • 今よりも同時実行数が上がれば、Active JobやSidekiqを捨て て自前で実装するかも
 ◦ 現在は1日10回未満の実行 
 • Dynoの同時実行数100を目一杯使いつつ、超えないようなジョ

    ブキューを

  31. まとめ
 • 途中で止めたくないバッチ処理があったので、One-Off Dyno での実行に変えた
 • メリットだらけで満足いく結果となった
 • ただしリトライ処理の実装は面倒で、工夫が必要だった


  32. ご清聴ありがとうございました