Slack / Discord 通知
学習ジョブは実質 2 つの待ちが続きます。最初に GPU の確保 (warm な GPU が残っていない場合は数分かかることもある cold start。理由は Quickstart 参照)、次に学習本体 (テンプレートで約 7〜12 分)。ブラウザータブをそんなに長くは見ていられません。終端のonCompleted と onFailed コールバックは、チームが普段いる場所にステータスメッセージを流すのに自然な場所です。本当に完了したときだけ振り返ればよくなります。
このレシピは Slack incoming Webhook を使います。Discord、Microsoft Teams、任意の HTTP エンドポイントも同じやり方で動きます。fetch できるものなら何でも通知先になります。
自分のためのデスクトップ通知だけで十分なら、Studio が
training.completed / training.failed 時にブラウザー通知・ページ内 toast・タブタイトルのインジケーターを出します (Run training をクリックして通知許可を受け入れた後で有効)。このレシピはそれをチームの共有チャンネルに飛ばすためのものです。パターン
<!here> メンションは失敗時にしか発火しないので、成功時は誰も呼び出しません。チームの学習ジョブが実際にどれだけ失敗するかに合わせて緊急度を調整してください。
なぜ内側の try / catch が大事か
Webhook リクエストが throw すると(Slack 障害、DNS の不調、コードが 200 番台以外を再 throw するなど)、コールバックは reject します。Arkor ランタイムはその reject を catch して SSE 再接続ループに送ります(SDK § ライフサイクルコールバック)。maxReconnectAttempts がデフォルトの無制限のままだと、不安定な Webhook が静かに永遠にリトライされ得て、リトライ間で Last-Event-ID が進めば元のイベントが飲み込まれます。
Webhook は学習成功の判定基準ではなく副作用として扱ってください。内側で catch、知りたければログに残す。
バリエーション
ステップごとの進捗 ping。onLog と組み合わせて N ステップごとに 1 行投稿:
process.env.NOTIFY_PROGRESS === "1" でゲートしてください。
学習中のサンプル共有。 学習中の評価レシピ と組み合わせる: 各チェックポイントのサンプルをレビューチャネルに投稿し、学習が続いている間に同僚がリアクションで反応できます。
capture()、Datadog のイベント、DB への insert: 形は同じです。副作用を自分でエラーを飲み込む async ヘルパーの裏に置き、ライフサイクルコールバックから呼ぶ。トレーナーファイルに追加のオーケストレーションは不要です。
心に留めておくこと
- 内側の
try / catchは必須。 通知は あれば便利、ですが Webhook の障害が学習イベントストリームを静かにリトライさせていいわけがありません。 - シークレットをトレーナーファイルに置かない。 例では
SLACK_WEBHOOK_URLをprocess.envから読み、Webhook がgitに入らないようにしています。トークンベースの宛先全般に同じ考え方を。 errorはstringであることを忘れない。onFailedのerror引数はバックエンドが送った文字列で(SDK § ライフサイクルコールバック)、Errorインスタンスではありません。直接埋め込み、.messageを呼んだりしないでください。