非同期 Jobs
クライアント間で長時間実行される作業を調整します。job を開始し、結果で解決し、どこからでも結果を待機できます。
Jobs を使用する理由
一部の作業は、単一のリクエストよりも長く続きます。大規模なレポートの生成、アップロードされたデータセットの処理、長時間実行される AI タスクなどです。作業を実行するコードと結果を待つコードは、多くの場合、別々の場所にあります。backend function が処理を行い、browser tab が結果を表示するために待機する、といった形です。
Jobs がない場合は、ステータス変更を確認するために database record をポーリングしたり、カスタム通知チャネルを構築したりする必要があります。Jobs を使用すると、producer は private ID のもとで job を開始し、完了時に解決します。そして、その ID を知っている任意の client が結果を待機できます。
// 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 単位を追跡する軽量な record です。in_progress、completed、failed のいずれかの status を持ち、解決後には result または error message を保持します。Jobs は client-owned です。caller が job ID を生成し、job を開始し、解決する責任を持ちます。Squid は owner が接続されている間 job を保持し、すべての waiter に結果を配信します。
Squid は、CLI agent model asks などの長時間実行される executions に対しても、内部的に同じ job の仕組みを使用します。これらも同じ getJob() と awaitJob() 呼び出しで追跡できます。
Jobs を使用する場面
| Use Case | Recommendation |
|---|---|
| Backend function が長時間の作業を実行し、client が待機する | Backend で job を開始し、ID を返し、client で awaitJob() します |
| 長時間実行される AI agent ask の進行状況を追跡する | jobId を ask() に渡すか askAsync() を使用し、その後 job を待機します |
| 進行中の作業の現在の status を確認する | getJob() |
| UI を database changes と同期させる | 代わりに real-time queries を使用します |
| Function を schedule で実行する | 代わりに scheduler を使用します |
仕組み
- Producer が一意で private な job ID を生成し、
startJob(jobId)を呼び出します - Squid が job を
in_progressとして mark します。owning client は自動的に job を alive に保ちます。owner が切断された場合、Squid は job を失敗させるため、waiter が待ち続けることはありません - Consumer は
awaitJob(jobId)を呼び出して結果を待つか、getJob(jobId)を呼び出して現在の status を poll します - Producer は
completeJob(jobId, result)またはfailJob(jobId, error)で job を解決します - Job がすでに完了した後に subscribe した waiter も含め、すべての waiter が result(または error)を受け取ります
Quick Start
最も一般的な pattern は、backend の executable が長時間実行される作業を開始し、job ID をすぐに返し、client がその job を待機する形です。
Step 1: Backend で job を開始して解決する
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));
}
}
}
Step 2: Client から job を待機する
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);
Core Concepts
Job ID は private capabilities です
Job ID は job に付与される唯一の credential です。job の ID を知っている人は誰でも、その status と result を読み取ることができます。ID は secret として扱ってください。
- 推測できない ID を生成します(例:
crypto.randomUUID()) - Job ID を再利用しないでください
- Result を見るべき client にのみ ID を共有してください
Jobs の開始と解決には API key が必要です。通常は backend(this.squid がすでに authenticated されている場所)または trusted server-side client です。Jobs の読み取りと待機には API key は不要で、ID だけが必要です。
Method reference
Jobs API には squid.job() でアクセスします。
| Method | Returns | API key required | Description |
|---|---|---|---|
startJob(jobId) | Promise<void> | Yes | この client が所有する job を開始します。既存の job に対しては idempotent です。 |
completeJob(jobId, result) | Promise<void> | Yes | この client が所有する job を、その result で正常に解決します |
failJob(jobId, error) | Promise<void> | Yes | この client が所有する job を、error message とともに failed として解決します |
getJob<T>(jobId) | Promise<AsyncJob<T> | undefined> | No | Job の現在の status と、completed の場合はその result を返します |
awaitJob<T>(jobId) | Promise<T> | No | Job が終了するまで待機します。result で解決するか、throw します |
AsyncJob type
getJob() は AsyncJob を返します。
| Field | Type | Description |
|---|---|---|
id | string | Job ID |
createdAt | Date | Job が開始された時刻 |
updatedAt | Date | 最後に status が変更された時刻 |
status | 'in_progress' | 'completed' | 'failed' | Job の現在の状態 |
result | T (optional) | status が 'completed' の場合に存在する result |
error | string (optional) | status が 'failed' の場合に存在する error message |
Ownership と keep-alive
startJob() を呼び出した client が job の owner であり、その job を解決できる唯一の client です。別の client の job を解決しようとすると NOT_JOB_OWNER error で失敗します。Owner が接続を維持している間、SDK は background でその jobs を自動的に alive に保ちます。
Owner が解決前に切断またはクラッシュした場合、Squid は Job failed due to client failover で job を失敗させます。また、gracefully shut-down された client は未解決の jobs を Client shut down で失敗させます。どちらの場合も、waiter は永遠に待機するのではなく、error とともに解放されます。
Job が terminal state に達すると、その状態のままになります。すでに解決済みの job に対する後続の completeJob() または failJob() は無視されます。
Waiting semantics
awaitJob()は すべての waiter に対して解決します。複数の clients が同じ job を待機でき、全員が result を受け取ります- Job がすでに完了した後に subscribe しても、terminal outcome ですぐに解決します
- Waiter は job の開始前に subscribe できます。まだ job が存在しない ID に対する
awaitJob()は単に待機し、job が開始されて完了すると resolve されます。裏を返せば、誤った ID や期限切れの job ID を待機すると無期限に待ち続けます。Error Handling を参照してください
Retention
Completed および failed jobs は、解決後およそ 1 時間 保持され、その後削除されます。結果は速やかに取得し、長期間必要なものは database または storage に永続化してください。In-progress jobs は sweep されません。解決されるか failover されるまで残ります。
AI Agents で Jobs を使用する
Agent asks は optional な job ID を受け取ることができ、これは長時間実行される requests に特に便利です。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);
ask() または chat() の最後の argument として jobId を渡すことで、blocking call を他の clients から追跡可能にすることもできます。ask() を通じて開始された jobs は、plain string ではなく AiAskResponse object で resolve されます。
CLI agent models(Claude Code や Codex など)を使用する asks は、完了まで数分かかることがあるため、内部的には常に long-running jobs として実行されます。jobId を提供すると、単一の request を開いたままにする代わりに、待機または poll するための handle を得られます。
Error Handling
| Error | Cause | Solution |
|---|---|---|
UNAUTHORIZED on startJob/completeJob/failJob | Client が API key で authenticated されていません | Backend、または API key で initialized された client から jobs を開始して解決します |
NOT_JOB_OWNER | Client が、別の client によって開始された job を解決しようとしました | Jobs は、それを開始した client からのみ解決してください |
awaitJob rejects with the job's error | Producer が failJob を呼び出したか、owner が切断されました | Rejection を handle し、原因を調べるために error message を確認します |
awaitJob never settles | Job ID が誤っているか、waiter が subscribe する前に job が期限切れになっています(解決後約 1 時間) | Job ID を確認し、結果を速やかに待機し、待機処理を独自の timeout でラップしてください |
Job fails with Failed to store job result | Result が storage size limit を超えました | 大きな payload は storage に保存し、reference で job を complete します |
Best Practices
- 推測できない job IDs を生成してください。 ID は job に対する唯一の access control です。
crypto.randomUUID()を使用し、連番や予測可能な値は使用しないでください。 - Jobs は必ず解決してください。 作業を
try/catchで wrap し、error 時にはfailJob()を呼び出して、waiter が generic な failover error ではなく意味のある failure を受け取れるようにします。 - Backend から開始して解決してください。 Backend code はすでに API key で authenticated されており、作業の duration の間接続を維持します。
- Results は小さく保ってください。 Compact な payload または reference で jobs を complete してください。大きな artifacts は storage または database に保存します。
- Retention window 内に results を取得してください。 Terminal jobs は解決後およそ 1 時間で削除されます。保持が必要なものは永続化してください。
Next Steps
- Executables - Jobs を開始して解決できる backend functions
- AI agents -
askAsync()を使用して agent asks を追跡可能な jobs として実行する - Database - Retention window を超えて job results を永続化する
- Distributed locks - Shared resources への concurrent access を調整する