バッチ監視の話をしよう - 数百本のバッチを運用して見えた勘所
これは何
バッチ監視と一口に言っても、単に「失敗を検知する」だけでは不十分なことがある。 本記事では、FOLIOのバッチを運用する中で得られた知見をもとに、「何をどのように監視すべきか」 を3つの観点から整理する。
JJUG CCC 2025 Fall の Lightning Talk で話をしたことを紹介する。 https://ccc2025fall.java-users.jp/
バッチシステムとは

株式会社FOLIOの4RAPというサービスでは、現時点において450を超えるバッチが存在している。日次で動くものもあれば、月次で動くようなものもあり、各コンポーネント毎に必要な処理が定期的に実施されている。
バッチ監視はどのようなことをしていますか?

どんなサービスにもバッチ処理はつきものかと思う。ジョブスケジューラをもとに発火するものがあれば、イベントをもとに発火するものもある。
これらのバッチの監視は何をしたら良いのだろうか?
ここでは基本的な例を順取り上げつつ、トピックごとにここまで考慮出来ると良いということを個別に説明したい。
1. バッチの「成功」を確認する

最もよくやられている監視として、バッチがエラーを出して落ちた場合の監視というものがあげられる。通常は失敗時にはExit Codeが1になるようにして処理を落として、バッチ基盤の仕組みを使いアラートまであげるのではないかと思う。
ここで注意したいのは何をもってバッチの「成功」とみなすか。
バッチが正常終了したことをもって結果整合性が取れているのがもちろん最も望ましい。一方で、そのバッチで分散トランザクションをしていたり、意図せず障害対応によりデータが書き換えられていたり...様々な要因で意図しないデータ不整合は起こり得る。サービスをまたいだ整合性の検知などは、必要に応じて別途リコンサイルなどのフローを設けることも検討が必要になる。
2. バッチの「実行開始」を検知する

次に確認したいのは、そもそもバッチが起動されているのか?ということ。cron syntaxで24時間設定をしたので、あとはバッチ基盤にのっていれば必ず動くでしょうという勘違いはある。バッチ基盤にはバッチ基盤なりのSLOが存在しており、大手のSaaSを使っていたとしても何かしらハードウェア障害などで意図せず処理がスキップされてしまう、k8のCronJobでもdeadline次第ではqueueingされたものが処理されないことはある。
24時間に1度動くようなバッチについては24時間+αに1度イベントが届いているかを確認したいし、マイクロバッチのようなシステムではハートビートが定期的に届いているかを確認したい。
3. バッチの「遅延」を検知する

ここで言う「遅延」とは、実行時間のことを指す。毎日12時に動き始めるバッチが13時までに終わって欲しい場合には、バッファを設けて閾値40分などで監視をしたい。
様々なバッチ基盤においては、バッチ処理が完了した際にイベントやメトリクスを送出していると思う。最も簡単な監視方法はそのイベントやメトリクスを見て、40分を超えていたら警告を鳴らすこと。
一方この方法でもデメリットが存在しており、仮に処理に60分を超えてしまった場合には、検知自体が60分を超えた時刻になってしまう問題がある。この問題の解決案として例としてk8s Jobなら activeDeadlineSeconds のような設定をすることも考えられるが、deadlineを超えた際にprocessを終了させてしまうような処理には注意が必要だ。仮に再実行をしたとしても、再実行性が考慮されていない場合に、また再実行の際にdeadlineによりprocessが落とされてしまうこともある。
処理時間の監視は、終了イベントではなく uptime のような実行中に定期的に送られるメトリクスで監視をすることが望ましい。それによりジョブが終了していなくても閾値を超えた際の検知が出来るし、仮に超えたとしても処理を止めるかは人が判断することが出来る。
再掲: バッチ監視はどのようなことをしていますか?

これ以外にもcpuやmemoryのようなリソース監視や、外部middlewareの監視など、バッチ処理に関わる監視は信頼性を向上させるためにも必要になってくる。
締め
たかがバッチ監視、されどバッチ監視。 監視設計の粒度が、バッチの信頼性と運用負荷を大きく左右します。 明日の朝を安心して迎えられるように、もう一度自分たちの監視を見直してみませんか?
Next.js 16ではturbopackがデフォルトとなったので、@svgr/webpackの処理もturbopackに移行する
これは何
Next.16にあげたときにエラーがでたものの、原因がすぐには分からなかったので同様の事象にはまった人に対する備忘録
Next.16にあげた際のエラー
いくつかのページで、以下のエラーが出た。
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

なぜこのエラーになったのか?
以下の利用をしている人はこの事象にあてはまる。
@svgr/webpackを利用している- next.config.jsで、webpackのrulesで
@svgr/webpackを処理させている - 該当のページで svgr で読み込ませたsvgをレンダリングしている
- turbopackをNext.js 16から使い始めた
@svr/webpack は、svg fileをReact Componentとして使うために利用している。
Next.js x webpack で利用する場合には、next.config.jsなどで設定を行っているかと思う。
Next.js 16ではturbopackがデフォルトで利用されるようになり、その設定が効かなくなっている(わかれば当たり前ではある)
対応方法
next.config.js で turbopack の設定として @svgr/webpack を処理させる
const nextConfig = { turbopack: { rules: { '*.svg': { loaders: ['@svgr/webpack'], as: '*.js' } } } };
@google/genai x Vertex AIで画像を編集させる
これは何
以下のものを利用して、画像編集を行う方法
- Google Gen AI SDK | Generative AI on Vertex AI | Google Cloud Documentation
- Vertex AI Platform | Google Cloud
やりたいこと
Google Gen AI SDKでは、Gemini Developer APIとVertex AIのいずれかを汎用的に利用できるSDKとなっている。
ユーザに指定された画像 + プロンプトに基づいて、画像の編集を行う方法について記載する
画像編集方法
権限追加
Vetex AIを叩ける権限をService Accountには追加する必要がある
resource "google_project_iam_member" "this" { for_each = toset([ // Vertex AIを利用できる権限の追加 "roles/aiplatform.user", ]) role = each.key member = "serviceAccount:${google_service_account.backend.email}" project = var.project_id } // 別途GCSへのアクセス権限の追加
変換処理
base64画像を直接扱う事もできるのだが、inputとしてもoutputとしてもgcs urlを受け付けられるため、サーバやジョブにおけるメモリ負荷を考慮してgcs urlで連携する方法を記載。
import { GoogleGenAI } from "@google/genai"; const client = new GoogleGenAI({ vertexai: true, // vertexai との統合(Vertex AIを利用しないなら、GEMINI_API_KEYなどを指定) project, location, }); const subject = new SubjectReferenceImage(); subject.referenceId = 1; subject.referenceImage = { gcsUri: referenceGcsUri, // 参考元画像: gcsとbufferを指定可能ではあるが、メモリ負荷を抑えるためにgcsを利用させることを推奨 }; subject.config = { subjectType: SubjectReferenceType.SUBJECT_TYPE_PERSON, // 人物編集 subjectDescription: "画像の説明", }; const response = await this.client.models.editImage({ model: "imagen-3.0-capability-001", // モデルの指定 prompt, // 編集のためのprompt指定 referenceImages: [reference], // 元画像の指定 config: { outputGcsUri: `gs://your-bucket/output/`, // こちらを指定すると、出力に gcs_url が含まれるため、この方法を推奨 numberOfImages: 1, // 生成画像数 negativePrompt: FALLBACK_NEGATIVE_PROMPTS.join(", "), // 禁止する処理を記載 personGeneration: PersonGeneration.ALL, // ADULT/ALL/DONT_ALLOWの指定 aspectRatio, // "1:1", "4:3",... などを指定 language: "auto", // 明示的に "ja" なども指定可能 outputMimeType, // "image/png", "image/jpeg".... などを指定 outputCompressionQuality: 0.7 // jpeg ならcompressionの指定が可能 // https://docs.cloud.google.com/vertex-ai/generative-ai/docs/image/configure-responsible-ai-safety-settings?hl=ja // サービスによっては責任あるAIの安全性設計が必要になるため、こちらのフラグを立てた後に、responseに含まれるcategoryやscoreを検証する safetyFilterLevel: SafetyFilterLevel.BLOCK_MEDIUM_AND_ABOVE, includeRaiReason: true, includeSafetyAttributes: true, }, }); // responseには複数画像のスコアやgcs_urlが含まれる
気軽にプログラムからも画像編集が出来て便利ですね。権利問題に気をつけて使っていきましょう。
備考
vertexにoutput gcsを利用させる権限付与した記憶がないのだが、どこで権限付与されているんだ。