Google Cloud Runでバッチ処理をやらせよう


まとめ

  • バッチ処理用のスクリプトとwebサーバー用のスクリプトを分けておくと開発が捗る
  • 所定のJSONをSTDOUTかSTDERRに流すとError Reportingにエラーを通知できる

ソースコード

Githubでforkしたリポジトリで、上流の変更をマージしています。こちらの詳細は別記事のGithub上のリポジトリの操作を自動化するdockerコンテナにて。

webserver.rb
require 'webrick'
require 'json'
srv = WEBrick::HTTPServer.new({ :DocumentRoot => './',
                                :BindAddress => '0.0.0.0',
                                :Port => ENV['PORT'].to_i})
srv.mount_proc '/' do |req, res|
  res.body = `sh -e ./main.sh 2>&1`
  STDOUT.puts res.body
  STDOUT.flush
  if $? != 0
    res.status = 500
    STDERR.puts JSON.generate(
      "@type": 'type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent',
      message: 'ジョブの実行に失敗しました'
    )
    STDERR.flush
  end
end
trap("INT"){ srv.shutdown }
srv.start
  • gem install をしなくて良いように、Rubyに標準で入っている機能を使っています
  • Google Cloud Runでは、コンテナの環境変数に、公開するポート番号がPORTで渡ってくるので、そのポート番号でサーバーを建てます
  • STDOUT/STDERRへの出力はそのままだとバッファリングされたままHTTPリクエストの処理が終わって出力されない場合があるので、明示的にflushしてます(STDOUT.sync = true とかでも良い)
  • Google Cloud Runには、ログをJSON形式で出力すると、自動的に構造化ログとしてStackdriver Loggingに送ってくれる機能があります
  • ログのJSONが所定の形式に従っていればエラーとみなしてError Reportingに報告してくれます
    • ここでは @type の指定がそれに該当します
    • スタックトレースを message に含める方法もあるようですが、そちらは未検証です
    • Error ReportingにはアカウントのGMailアドレスに通知メールを送ってくれる機能があります
  • Rubyのシェル実行機能を使って、本体である main.sh の処理を起動しています
    • 終了ステータスを$?で取得しています
  • 定時実行のトリガーはCloud Schedulerを使います
    • Cloud Scheduler上ではHTTPステータスで成否を判断しているので、それにあわせてHTTPステータスを返すようにしています(エラー通知はログ経由で受け取っているので現状はあまり意味はありません)