Asynchronous Jobs
client 間で長時間実行作業を調整します。job を開始し、result で resolve して、どこからでも outcome を await できます。
Jobs を使用する理由
一部の作業は単一 request より長く続きます。たとえば、大規模 report の生成、upload された dataset の処理、長時間実行 AI task などです。作業を実行する code と result を待機する code は、多くの場合異なる場所にあります。backend function が processing を実行し、browser tab が outcome を表示するために待機します。
jobs がなければ、status change を database record で poll するか、custom notification channel を構築する必要があります。jobs では、producer が private ID で job を開始し、完了時に resolve します。ID を知る任意の client が result を await できます。
// Producer: start the job, do the work, resolve it
const jobId = crypto.randomUUID();
await squid.job().startJob(jobId);
const result = await doLongRunningWork();
await squid.job().completeJob(jobId, result);
// Consumer: any client that knows the job ID
const result = await squid.job().awaitJob(jobId);
jobs API は現在 TypeScript Client SDK で利用できます。Python client には jobs API は含まれていません。
概要
job は、1 単位の asynchronous work を追跡する軽量な record です。status(in_progress、completed、failed)と、resolve 後の result または error message を保持します。job は client-owned です。caller が job ID を生成して job を開始し、resolve する責任を持ちます。Squid は owner が接続されている間 job を維持し、outcome をすべての waiter に配信します。
Squid は CLI agent model の ask など、長時間実行される execution にも同じ job mechanism を内部的に使用します。これらも同じ getJob() と awaitJob() call で追跡できます。
Jobs を使用する場合
| ユースケース | 推奨 |
|---|---|
| backend function が長時間作業を実行し、client が待機する | backend で job を開始して ID を返し、client で awaitJob() を使用 |
| 長時間実行 AI agent ask の progress を追跡する | ask() に jobId を渡すか、askAsync() を使用して job を await |
| 実行中の作業の current status を確認する | getJob() |
| database change と UI を同期させる | 代わりに real-time queries を使用 |
| schedule に従って function を実行する | 代わりに scheduler を使用 |
仕組み
- producer が unique かつ private な job ID を生成し、
startJob(jobId)を呼び出します - Squid が job を
in_progressとしてマークします。owner client は自動的に job を維持します。owner が disconnect すると、waiter が待機したままにならないよう Squid が job を fail します - consumer は outcome を待つために
awaitJob(jobId)を呼び出すか、current status を poll するためにgetJob(jobId)を呼び出します - producer が
completeJob(jobId, result)またはfailJob(jobId, error)で job を resolve します - job がすでに完了した後に subscribe した waiter を含め、すべての waiter が result または error を受け取ります
クイックスタート
最も一般的な pattern は、backend executable が長時間実行 work を開始してすぐに job ID を返し、client が job を await する方法です。
ステップ 1: Backend で job を開始・resolve する
import { executable, SquidService } from '@squidcloud/backend';
export class ReportService extends SquidService {
@executable()
async startReportGeneration(reportType: string): Promise<string> {
this.assertIsAuthenticated();
const jobId = crypto.randomUUID();
await this.squid.job().startJob(jobId);
// Run the work out-of-band; the executable returns immediately.
this.generateReport(jobId, reportType);
return jobId;
}
private async generateReport(jobId: string, reportType: string): Promise<void> {
try {
const report = await this.buildReport(reportType); // Long-running work
await this.squid.job().completeJob(jobId, report);
} catch (error) {
await this.squid.job().failJob(jobId, String(error));
}
}
}
ステップ 2: Client から job を await する
const jobId = await squid.executeFunction('startReportGeneration', 'quarterly');
// Resolves with the report once the backend completes the job,
// or throws if the backend fails it.
const report = await squid.job().awaitJob(jobId);
コアコンセプト
Job ID は private capability である
job ID は job に紐付く唯一の credential です。job ID を知る人は誰でも、その job の status と result を読み取れます。ID は secret として扱ってください。
- 推測不可能な ID を生成します(例:
crypto.randomUUID()) - job ID を再利用しません
- result を確認すべき client とのみ ID を共有します
job の開始と resolve には API key が必要です。通常は backend(this.squid がすでに認証済み)または信頼された server-side client から実行します。job の読み取りと待機に必要なのは ID のみで、API key は必要ありません。
Method reference
jobs API には squid.job() で access します。
| Method | Returns | API key が必要 | 説明 |
|---|---|---|---|
startJob(jobId) | Promise<void> | はい | この client が owner となる job を開始します。既存 job に対して idempotent です。 |
completeJob(jobId, result) | Promise<void> | はい | この client が owner の job を result で正常に resolve します |
failJob(jobId, error) | Promise<void> | はい | この client が owner の job を error message とともに failed として resolve します |
getJob<T>(jobId) | Promise<AsyncJob<T> | undefined> | いいえ | job の current status と、完了している場合は result を返します |
awaitJob<T>(jobId) | Promise<T> | いいえ | job が完了するまで待機し、result で resolve または error を throw します |
AsyncJob type
getJob() は AsyncJob を返します。
| Field | Type | 説明 |
|---|---|---|
id | string | job ID |
createdAt | Date | job が開始された時刻 |
updatedAt | Date | 最後の status change |
status | 'in_progress' | 'completed' | 'failed' | job の current state |
result | T(optional) | status が 'completed' の場合に存在する result |
error | string(optional) | status が 'failed' の場合に存在する error message |
Ownership と Keep-alive
startJob() を呼び出した client が job の owner であり、job を resolve できる唯一の client です。他の client が開始した job を resolve すると、NOT_JOB_OWNER error で失敗します。owner が接続されている間、SDK は background でその job を自動的に維持します。
owner が resolve 前に disconnect または crash した場合、Squid は Job failed due to client failover で job を fail します。graceful に shutdown された client は、未解決 job を Client shut down で fail します。どちらの場合も、waiter は永久に待機するのではなく error で解放されます。
job が terminal state に達すると、その state が維持されます。すでに resolve 済みの job に対する遅延した completeJob() または failJob() は無視されます。
Waiting semantics
awaitJob()はすべての waiter に対して resolve します。複数の client が同じ job を await でき、全員が result を受け取ります- job がすでに完了した後に subscribe しても、terminal outcome で直ちに resolve します
- waiter は job の開始前に subscribe できます。まだ job がない ID に対する
awaitJob()は単に待機し、job が開始され完了すると resolve します。一方で、typo のある job ID や期限切れ job ID を await すると無期限に待機します。Error Handling を参照してください
Retention
completed および failed job は、resolve 後に約 1 時間保持され、その後削除されます。result は速やかに取得し、長期的に必要なものは database または storage に永続化してください。in-progress job は sweep されません。resolve または failover されるまで保持されます。
AI Agents での Jobs の使用
agent ask は optional な job ID を受け取ります。これは長時間実行 request で特に役立ちます。askAsync() を使用して blocking せずに request を送信し、jobs API を通じて追跡します。
const jobId = crypto.randomUUID();
// Returns immediately; the ask runs as a job.
await squid.ai().agent('research-assistant').askAsync('Analyze the quarterly report', jobId);
// Await the answer whenever (and wherever) you need it.
// An askAsync job resolves with the agent's answer as a plain string.
const answer = await squid.job().awaitJob<string>(jobId);
他の client からも追跡可能な blocking call を作成するには、ask() または chat() の最後の argument として jobId を渡すこともできます。ask() を通じて開始された job は plain string ではなく AiAskResponse object で resolve されます。
Claude Code や Codex などの CLI agent modelを使用する ask は、完了までに数分かかる可能性があるため、常に internal の長時間実行 job として実行されます。jobId を指定すると、単一 request を開いたままにする代わりに await または poll するための handle を取得できます。
Error Handling
| Error | 原因 | 解決策 |
|---|---|---|
startJob/completeJob/failJob での UNAUTHORIZED | client が API key で認証されていない | backend または API key で初期化した client から job を開始・resolve する |
NOT_JOB_OWNER | client が別の client により開始された job を resolve しようとした | job を開始した client からのみ job を resolve する |
awaitJob が job の error で reject される | producer が failJob を呼び出した、または owner が disconnect した | rejection を処理し、原因を error message で確認する |
awaitJob が完了しない | job ID が誤っている、または waiter が subscribe する前に job が期限切れになった(resolve 後約 1 時間) | job ID を確認し、速やかに result を await し、独自の timeout で wait をラップする |
Job が Failed to store job result で失敗する | result が storage size limit を超過している | 大きな payload は storage に保存し、reference を指定して job を complete する |
ベストプラクティス
- 推測不可能な job ID を生成する。 ID は job の唯一の access control です。
crypto.randomUUID()を使用し、sequential または予測可能な value は使用しないでください。 - 常に job を resolve する。 work を
try/catchでラップし、error 時にfailJob()を呼び出します。これにより、waiter は generic な failover error ではなく意味のある failure を受け取れます。 - backend から開始・resolve する。 backend code はすでに API key で認証されており、作業期間中は接続が維持されます。
- result を小さく保つ。 compact payload または reference で job を complete します。大きな artifact は storage または database に保存してください。
- retention window 内で result を取得する。 terminal job は resolve 後約 1 時間で削除されます。保持が必要なものは永続化してください。
次のステップ
- Executables - job を開始・resolve できる backend function
- AI agents -
askAsync()を使用して agent ask を追跡可能な job として実行する - Database - retention window を超えて job result を永続化する
- Distributed locks - shared resource への concurrent access を調整する