SDK query()の改善:forループのbreakやusing宣言でサブプロセスを自動クリーンアップ
原文(日本語に翻訳)
for await からの break や await using の使用時にサブプロセスと一時ファイルをクリーンアップするよう SDK query() を改善
原文(英語)
Improved SDK query() to clean up subprocess and temp files when consumers break from for await or use await using
概要
Claude Agent SDKの query() 関数は非同期イテレータを返しますが、for await ループを途中で break した場合や await using 構文でリソースを解放した場合に、内部で起動するサブプロセスや一時ファイルが適切にクリーンアップされない問題が修正されました。長時間動作するアプリケーションやCLIツールでリソースリークを防ぐために重要な改善です。
基本的な使い方
for await ループでのbreak(修正後)
typescript
import { query } from "@anthropic-ai/claude-code";
// breakしても内部リソースが自動クリーンアップされる
for await (const message of query({ prompt: "大きなタスクを実行して" })) {
if (message.type === "result" && message.subtype === "success") {
console.log("完了:", message.result);
break; // 修正後: サブプロセスと一時ファイルが自動クリーンアップ
}
}await using 構文(TypeScript 5.2+)
typescript
import { query } from "@anthropic-ai/claude-code";
async function runTask() {
// await using によって自動的にクリーンアップが保証される
await using session = query({ prompt: "タスクを実行して" });
for await (const message of session) {
console.log(message);
// スコープを抜けると自動的にクリーンアップ
}
}実践例
条件付き早期終了のパターン
typescript
import { query } from "@anthropic-ai/claude-code";
async function findFirst(searchTerm: string): Promise<string | null> {
for await (const message of query({
prompt: `"${searchTerm}" を含む最初のファイルを教えて`
})) {
if (message.type === "result" && message.subtype === "success") {
return message.result; // breakせずreturnでも正しくクリーンアップ
}
// エラーの場合は早期終了
if (message.type === "result" && message.subtype === "error") {
break; // 修正後: リソースが正しく解放される
}
}
return null;
}タイムアウト付きの実行
typescript
import { query } from "@anthropic-ai/claude-code";
async function queryWithTimeout(prompt: string, timeoutMs: number) {
const timeoutPromise = new Promise<never>((_, reject) => {
setTimeout(() => reject(new Error("タイムアウト")), timeoutMs);
});
try {
for await (const message of query({ prompt })) {
// タイムアウトが発生してもサブプロセスはクリーンアップされる
if (message.type === "result") {
return message;
}
}
} catch (error) {
// エラー時もリソースは適切に解放される
console.error("エラー:", error);
throw error;
}
}長時間動作するサーバーアプリケーション
typescript
import { query } from "@anthropic-ai/claude-code";
import express from "express";
const app = express();
app.post("/analyze", async (req, res) => {
try {
// リクエストごとにquery()を呼び出す
// 修正前: 各リクエスト後にサブプロセスが残留し、サーバーがリソース枯渇
// 修正後: 各リクエスト完了後に自動クリーンアップ
for await (const message of query({
prompt: req.body.code,
options: { /* ... */ }
})) {
if (message.type === "result" && message.subtype === "success") {
res.json({ result: message.result });
return; // returnでもクリーンアップが保証される
}
}
} catch (error) {
res.status(500).json({ error: String(error) });
}
});await using を使った確実なクリーンアップ(TypeScript 5.2+)
typescript
import { query } from "@anthropic-ai/claude-code";
// tsconfig.json で "target": "ES2022" 以上が必要
async function processWithGuaranteedCleanup() {
await using iterator = query({ prompt: "データを処理して" });
for await (const event of iterator) {
if (event.type === "text") {
process.stdout.write(event.text);
}
if (event.type === "result") {
break; // スコープを抜けると await using が自動クリーンアップ
}
}
// ここでクリーンアップが実行される
}注意点
- TypeScript/JavaScript SDK向け: この修正はClaude Code SDK(
@anthropic-ai/claude-code)に関するものです await usingの要件:await using構文はTypeScript 5.2以上と"target": "ES2022"以上が必要です- 以前の回避策: 以前は
try/finallyブロックで手動クリーンアップが必要でしたが、修正後は不要です - 長寿命プロセスへの影響: Webサーバーや長時間動作するCLIツールでSDKを使用している場合、この修正によるリソースリークの解消が特に重要です