プロビジョニングジョブを作成すると、pjb_ ジョブ ID と eng_ エンジン ID がミリ秒単位で返ってきます。エンジンはすでに使えますが、まだ中身は埋まり続けています。AI エージェントがソースをクロールし、ブランドボイス、用語集項目、指示を書き込んでいる最中です。だからこそ、その間の動きを見せたくなるはずです。何も伝えないスピナーではなく、インストールウィザードのように「スタイルガイドをクロール中… エンジンを設定中… 完了」と表示したい場面です。
このWebSocketは、まさにそのためのフィードです。ジョブに接続すると、サーバーはまず現在の状態のスナップショットをプッシュし、その後はワークフローが新しいステップに進むたびに provisioning.progress イベントを送ります。しかも、サーバーは接続時点の状態を返し、ジョブが完了済みならその直後に接続を閉じるので、完了後であってもいつでも接続できます。取り逃がしてはいけない時間帯はありません。
GET /jobs/provisioning/:jobId/wsjobId は、create 呼び出しで返る pjb_ の値です。非同期プロビジョニングが初めてなら、まずは全体像をつかむために 概要 から読むのがおすすめです。
このページの内容
メッセージタイプ#
このソケットを流れるメッセージタイプは2つです。1つ目は接続時に一度だけ届き、2つ目はジョブの進行に合わせて繰り返し届きます。
| タイプ | タイミング | 主なフィールド |
|---|---|---|
provisioning.snapshot | 初回接続時 | jobId、status、errorMessage |
provisioning.progress | 各ワークフローステップの開始時または完了時 | jobId、step、detail |
これは結果を返すフィードではなく、稼働状況を知らせるフィードです。分かるのはジョブが今どこにいて、失敗したかどうかであり、AI がどのレコードを作成したかではありません。プロビジョニングされた内容の要約、つまりブランドボイス、用語集、指示の ID は、完了 webhook で別途届くか、ジョブ完了後にそのジョブを読み出して取得します。ソケットは進行バー用に、実際のペイロードは webhook で受け取ってください。
接続時のスナップショット#
接続した瞬間、サーバーはデータベースからジョブの現在状態を読み取り、そのまま送信します。先に進行イベントが発生している必要はありません。スナップショットだけで成立します。
{
"type": "provisioning.snapshot",
"jobId": "pjb_A1b2C3d4E5f6G7h8",
"status": "in_progress",
"errorMessage": null
}| フィールド | 説明 |
|---|---|
status | in_progress、completed、または failed。 |
errorMessage | status が failed のときの失敗内容。それ以外では null です。 |
スナップショットは、受信が保証されている唯一のメッセージです。ジョブがまだ実行中なら、その後に進行イベントが届きます。すでに完了している場合は、届くのはスナップショットだけで、それ以上は何も送られません(以下を参照)。
進行イベント#
ワークフローの実行中、サーバーは新しいステップに入るたびに provisioning.progress イベントをブロードキャストします。各イベントには step が入り、人が読める detail も含まれます。
{
"type": "provisioning.progress",
"jobId": "pjb_A1b2C3d4E5f6G7h8",
"step": "crawling",
"detail": "Crawling source URLs..."
}step | タイミング | detail の例 |
|---|---|---|
crawling | ソースURLを取得中 | "Crawling source URLs..." または "Retrying crawl (attempt 2)..." |
configuring | AI エージェントがコンテンツを分析し、エンジン設定を書き込んでいる | "AI agent analyzing content and configuring engine..." または "Retrying configuration (attempt 2)..." |
completed | ジョブが正常に完了した | "Provisioning complete" |
failed | ジョブが失敗した | 失敗理由を説明するエラーメッセージ |
リトライは失敗ではありません
crawling と configuring のステップは、複数回発生することがあります。一時的な取得エラーや解析エラーが起きるとリトライされ、そのリトライは detail に "Retrying crawl (attempt 2)..." のような値を持つ進行イベントとして現れます。これはジョブが回復している状態であって、失敗ではありません。終了状態として扱うべきなのは failed ステップだけで、実際の理由はその detail に入ります。
知らないステップも処理できるようにする
新しい step の値は、今後追加される可能性があります。既知のステップだけを分岐対象にし、completed と failed をソケットを閉じる2つのステップとして扱い、それ以外は情報として無視してください。前方互換性のあるクライアントなら、更新なしでも動き続けられます。
ジョブ完了後の接続#
進行状況ソケットで悩ましいのは、接続が遅れたときに何が起きるかです。クロール完了後だったら、デプロイでタブが再接続した直後だったら、あるいはジョブがすでに失敗していたら。ここでの答えは、スナップショットの仕組みそのものに組み込まれています。
ジョブがすでに completed または failed に達している場合、サーバーはその最終 status(失敗していれば errorMessage も)を含むスナップショットを送信し、すぐに接続を閉じます。再生する進行イベントはありません。最終状態そのものがスナップショットだからです。まだ進行中のジョブは接続を開いたまま進行状況を流し続け、完了済みのジョブは結果を渡して切断します。
どちらの場合でも、最初のメッセージを見れば現在地が分かります。完了後であってもいつでも接続できます。早すぎることも、遅すぎることもありません。
UIへの組み込み#
pjb_ ジョブ ID に対してソケットを開き、スナップショットを読んで初期状態を設定し、その後は各進行イベントで更新して、ジョブが completed または failed に達したら閉じます。
import WebSocket from "ws";
const jobId = "pjb_A1b2C3d4E5f6G7h8";
const ws = new WebSocket(
`wss://api.lingo.dev/jobs/provisioning/${jobId}/ws`,
{ headers: { "X-API-Key": process.env.LINGO_API_KEY } }
);
ws.on("message", (raw) => {
const event = JSON.parse(raw);
switch (event.type) {
case "provisioning.snapshot":
console.log(`status: ${event.status}`);
break;
case "provisioning.progress":
console.log(`${event.step}: ${event.detail}`);
if (event.step === "completed" || event.step === "failed") {
ws.close();
}
break;
}
});クロールが問題なく進み、設定処理が段階的に表示されるジョブで動かしてみましょう。
status: in_progress
crawling: Crawling source URLs...
configuring: AI agent analyzing content and configuring engine...
completed: Provisioning complete画面上で起きる流れはこれで一通りです。ジョブは in_progress で始まり、クロールを経て設定へ進み、completed になればエンジンのプロビジョニングが完全に完了したことが分かります。接続が遅れた場合でも、同じループで正しく処理できます。完了済みのジョブは最終 status を含むスナップショットを1つ送ってソケットを閉じるだけなので、ライブ実行を処理するコードが特別な分岐なしでそのまま再生ケースにも対応できます。
APIキーはサーバー側で保持する#
このソケットは API キーで認証します。REST エンドポイントと同じ organization-scoped key です。このキーは組織内のすべてのエンジンに届くため、接続を開く場所としてブラウザは不適切です。ソースを見れば、誰でもそのキーを見られてしまいます。
接続はブラウザではなくバックエンドから
WebSocket は、キーがすでにあるサーバーから開き、その後は自分で管理するチャネル経由で進行状況をブラウザへ転送してください。たとえば WebSocket や Server-Sent Events のストリームです。フロントエンドにはエンジンが設定されていく様子だけが表示され、キーが自社インフラの外に出ることはありません。
これは webhook モデルと同じ考え方です。Lingo.dev に接続する処理はサーバー側で行い、ユーザーに届くのは自分のアプリが転送すると決めた情報だけにします。
この機能の位置づけ#
WebSocket はライブビューです。1つのジョブにひもづき、そのジョブが完了すると閉じます。タブを閉じたあとやデプロイ後でも残る、結果の永続的なサーバー間記録が必要なら、完了 webhook と組み合わせてください。ジョブが画面に出ている間はソケットが進行バーを動かし、AI が作成した内容の要約は到着した瞬間に webhook が届けます。どちらも同じ create 呼び出し から設定できます。
