🔥
ConvexのperformAsyncSyscallエラー完全解決ガイド
概要
ConvexのNode.js環境で発生するperformAsyncSyscallエラーの根本原因と解決方法について、実際の対応事例を基に詳しく解説します。このエラーは、ConvexのNode.js Action内でConvexランタイムAPIを呼び出す際に発生する、非常に根深い問題です。
問題の発生状況
エラーメッセージ
Error: performAsyncSyscall can only be called from within a Convex function
発生環境
-
Convex Node.js Action環境 (
"use node"を使用) - AI処理関数内でのデータベース操作時
- 並列処理でのランタイム境界問題
初期コード例
"use node";
export const processAudioFileAnalysis = internalAction({
handler: async (ctx, args) => {
// ❌ Node.js環境でConvexランタイムAPIを呼び出し
await ctx.runMutation(internal.genAIResults.updateEvaluationResult, {
transcriptionId: args.transcriptionId,
result: evaluationResult,
status: "completed",
});
},
});
根本原因の分析
Convexのランタイム境界
Convexには以下のランタイム境界があります:
- V8 Isolate環境 - 通常のQuery/Mutation
-
Node.js環境 -
"use node"を使用したAction -
ランタイムAPI -
ctx.runQuery,ctx.runMutation,ctx.runAction
performAsyncSyscallの役割
performAsyncSyscallは、ユーザー関数とConvexサーバー間の内部APIブリッジです。Node.js環境からConvexランタイムAPIを呼び出す際に、ランタイム境界を越えることで発生するエラーです。
解決過程(試行錯誤の記録)
第1段階:ctx.runQueryの削除
// ❌ 失敗:まだperformAsyncSyscallエラーが発生
// ctx.runQueryを削除してパラメータ直接渡し
const transcriptText = args.transcriptionData.text; // パラメータで直接渡す
第2段階:ctx.runActionの削除
// ❌ 失敗:まだperformAsyncSyscallエラーが発生
// 並列Action呼び出しを内部ヘルパー関数に変更
const evaluationResult = await runEvaluationHelper(transcriptText);
第3段階:ctx.runMutationの削除
// ✅ 成功:performAsyncSyscallエラーが解消
// Node.js環境からすべてのConvexランタイムAPIを削除
export const processAudioFileAnalysis = internalAction({
handler: async (ctx, args) => {
// AI処理のみ実行、結果を返却
const evaluationResult = await runEvaluationHelper(transcriptText);
const meetingMinutesResult = await runMeetingMinutesHelper(transcriptText);
// ❌ ctx.runMutation呼び出しを削除
// ✅ 結果のみ返却
return {
success: true,
results: {
evaluation: evaluationResult,
meetingMinutes: meetingMinutesResult,
},
};
},
});
最終的な解決策
アーキテクチャの分離
Before (問題のある構造)
processAudioFileAnalysis (Node.js環境)
├── AI処理
└── ctx.runMutation ❌ performAsyncSyscallエラー
After (解決後の構造)
processWithSpeakerTranscription (Action環境)
├── processAudioFileAnalysis (Node.js環境)
│ ├── AI処理のみ
│ └── 結果を返却 ✅
└── ctx.runMutation (Action環境) ✅
実装コード
Node.js環境:AI処理専用
"use node";
export const processAudioFileAnalysis = internalAction({
handler: async (ctx, args) => {
// ✅ AI処理のみ実行
const evaluationResult = await runEvaluationHelper(transcriptText);
const meetingMinutesResult = await runMeetingMinutesHelper(transcriptText);
// ✅ 結果のみ返却(データベース操作なし)
return {
success: true,
results: {
evaluation: evaluationResult,
meetingMinutes: meetingMinutesResult,
},
};
},
});
Action環境:データベース操作
export const processWithSpeakerTranscription = internalAction({
handler: async (ctx, args) => {
// ✅ Node.js環境のAI処理を呼び出し
const analysisResult = await ctx.runAction(
internal.googleGenAIActions.processAudioFileAnalysis,
{ transcriptionId, transcriptionData }
);
// ✅ Action環境でデータベース保存
if (analysisResult?.success && analysisResult.results) {
await ctx.runMutation(internal.genAIResults.updateEvaluationResult, {
transcriptionId,
result: analysisResult.results.evaluation.result,
status: "completed",
});
}
},
});
重要な学習ポイント
1. ランタイム境界の理解
- Node.js環境内ではConvexランタイムAPIを使用してはいけない
-
ctx.runQuery,ctx.runMutation,ctx.runActionは通常のAction環境でのみ使用
2. 責任の分離
- Node.js環境: 外部API呼び出し、AI処理など
- Action環境: Convexデータベース操作、ランタイムAPI呼び出し
3. エラーの段階的解決
performAsyncSyscallエラーは、以下の順序で発生源を特定:
-
ctx.runQuery→ パラメータ直接渡しで解決 -
ctx.runAction→ ヘルパー関数で解決 -
ctx.runMutation→ 呼び出し元移動で解決
今後の対策
設計原則
// ✅ 良い設計
"use node";
export const nodeJsAction = internalAction({
handler: async (ctx, args) => {
// Node.js環境では外部処理のみ
const aiResult = await callExternalAI(args.text);
return { result: aiResult }; // 結果のみ返却
},
});
// 呼び出し元でデータベース操作
export const callerAction = internalAction({
handler: async (ctx, args) => {
const result = await ctx.runAction(internal.nodeJsAction, args);
await ctx.runMutation(internal.saveResult, result); // ✅
},
});
チェックポイント
-
Node.js環境で
ctx.runQuery/runMutation/runActionを使用していないか - AI処理とデータベース操作が適切に分離されているか
- 並列処理でランタイム境界を越えていないか
まとめ
performAsyncSyscallエラーは、ConvexのNode.js環境とランタイムAPI間の境界問題が原因です。AI処理とデータベース操作の完全分離により根本解決が可能です。このアーキテクチャにより、Convexの制約に準拠しながら複雑なAI処理システムを構築できます。
Discussion