メインコンテンツまでスキップ

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 を使用

仕組み​

  1. producer が unique かつ private な job ID を生成し、startJob(jobId) を呼び出します
  2. Squid が job を in_progress としてマークします。owner client は自動的に job を維持します。owner が disconnect すると、waiter が待機したままにならないよう Squid が job を fail します
  3. consumer は outcome を待つために awaitJob(jobId) を呼び出すか、current status を poll するために getJob(jobId) を呼び出します
  4. producer が completeJob(jobId, result) または failJob(jobId, error) で job を resolve します
  5. job がすでに完了した後に subscribe した waiter を含め、すべての waiter が result または error を受け取ります

クイックスタート​

最も一般的な pattern は、backend executable が長時間実行 work を開始してすぐに job ID を返し、client が job を await する方法です。

ステップ 1: Backend で job を開始・resolve する​

Backend code
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 する​

Client code
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 します。

MethodReturnsAPI 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 を返します。

FieldType説明
idstringjob ID
createdAtDatejob が開始された時刻
updatedAtDate最後の status change
status'in_progress' | 'completed' | 'failed'job の current state
resultT(optional)status が 'completed' の場合に存在する result
errorstring(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 を通じて追跡します。

Client code
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 での UNAUTHORIZEDclient が API key で認証されていないbackend または API key で初期化した client から job を開始・resolve する
NOT_JOB_OWNERclient が別の 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 する

ベストプラクティス​

  1. 推測不可能な job ID を生成する。 ID は job の唯一の access control です。crypto.randomUUID() を使用し、sequential または予測可能な value は使用しないでください。
  2. 常に job を resolve する。 work を try/catch でラップし、error 時に failJob() を呼び出します。これにより、waiter は generic な failover error ではなく意味のある failure を受け取れます。
  3. backend から開始・resolve する。 backend code はすでに API key で認証されており、作業期間中は接続が維持されます。
  4. result を小さく保つ。 compact payload または reference で job を complete します。大きな artifact は storage または database に保存してください。
  5. 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 を調整する