代碼節點凍結
描述問題/錯誤/問題
我的工作流程運作完美,但當我將記憶體附加到 LLM (OpenAI),它幾乎位於工作流程的中間。許多代碼節點在 http 節點之前(用於將有效負載發送到儀表板)
我遇到了嚴重的性能問題,其中我的代碼節點凍結,最終超時,但僅當 LLM 記憶體存在於工作流程中時。
我的工作流程使用幾個標準代碼節點處理傳入的 JSON 數據(執行數據清理和驗證)。在工作流程中進一步往下,我有一個 LLM 節點 (OpenAI),附加了記憶體組件。
當我運行工作流程不含 LLM 記憶體時,一切執行完美且立即完成。但是,一旦我將記憶體附加到 LLM,在 HTTP 請求節點之前執行的幾個代碼節點就會陷入無限掛起。
錯誤訊息是什麼(如果有的話)?
類似這樣:已經沒有錯誤訊息了,只是無限執行。錯誤:
任務執行在 300 秒後超時
任務運行器在此任務上耗時過長,因此被懷疑無法響應並重新啟動,任務被中止。您可以嘗試以下操作:1. 優化您的腳本以防止長時間運行的任務,例如通過以較小的批次處理數據。2. 確保您的腳本中的所有路徑都能終止,即沒有無限循環。3. 如果您的任務合理上可能需要超過 300 秒,請使用 N8N_RUNNERS_TASK_TIMEOUT 環境變數增加超時。
您的 n8n 設置信息
- n8n 版本: 2.11.3
- 數據庫(預設:SQLite): 預設
- n8n EXECUTIONS_PROCESS 設置(預設:own, main): 預設
- 通過以下方式運行 n8n(Docker、npm、n8n cloud、桌面應用程式): Dockers
- 操作系統: Windows
嘿 @sherazbintahir,在等待回覆時,這些資源可能會有所幫助:
建議的資源
自動符合您的問題。
文件:
論壇:
@Fabian_Hagen、@aseefdurrani、@Anshul_Namdev - 你們之前幫助過類似的問題,能看一下嗎?
由 n8n 社群機器人自動建議。這是試點計畫 - 請在此分享回饋。
是 n8n 的一項特定保障措施。這表示您 Code 節點 內的 JavaScript 程式碼運行時間超過 300 秒,導致 n8n Task Runner 假設它卡在無限迴圈或處理一個不可能的龐大任務中,因此將其強制終止。
由於這 只會 在您將 Memory 連接到 LLM 時發生,Memory 元件基本上改變了流入下游 Code 節點的資料結構、大小或行為。
當連接 Memory 時,LLM 節點(或它所屬的 chain/agent)可能會將 整個對話歷史記錄 或一個龐大的 memory 狀態物件傳遞到主資料流中,而不是僅傳遞最終的 AI 回應。
- 問題: 如果您的 Code 節點試圖處理、清理或
JSON.stringify() 一個現在包含數百或數千條歷史訊息的輸入,它將輕易超過 300 秒的 CPU 逾時。
- 解決方案: 您需要在 LLM 節點之後立即去除資料,只保留儀表板需要的部分。
- 在 LLM 節點之後添加一個臨時 Code 節點,使用以下程式碼查看實際傳遞的內容:
// 檢查項目數量和資料大小
const items = $input.all();
console.log("總項目數:", items.length);
console.log("第一個項目的鍵:", Object.keys(items[0].json));
return items;
- 如果您看到一個龐大的
messages 陣列或 memory 物件,請更新您的下游 Code 節點,以 只提取您需要的特定欄位(例如 item.json.message.content 或 item.json.text),並在處理前捨棄其餘部分。
n8n 中的 Memory 物件(特別是在處理 LangChain 整合時)有時可能包含 循環參考(其中物件參考自己)。
- 問題: 如果您的 Code 節點使用
JSON.stringify($input.all()) 或將整個輸入物件傳遞到自訂解析函數中,循環參考可能導致 JavaScript 引擎在試圖序列化物件時陷入無限迴圈,導致 300 秒逾時。
- 解決方案: 如果它包含 LLM/Memory 輸出,永遠不要字符串化整個
$input 或 $input.all()。始終先提取原始字符串值:
// 不好:如果存在循環參考可能會掛起
// const payload = JSON.stringify($input.all());
// 好:只提取您需要的原始資料
const cleanData = $input.all().map(item => ({
response: item.json.message?.content || item.json.text,
// 在此處添加其他特定欄位
}));
const payload = JSON.stringify(cleanData);
如果您的 Code 節點使用依賴於傳入 JSON 結構的 while 迴圈、遞迴函數或 .reduce() 方法,Memory 元件的添加可能已改變了該結構。
- 問題: 例如,如果您的程式碼有一個
while 迴圈處理陣列直到它為空,但 Memory 元件意外注入了一個不斷重新生成或不符合退出條件的嵌套陣列,迴圈將永遠運行。
- 解決方案: 檢查您的 Code 節點中的所有
while 迴圈。添加一個「安全計數器」以強制它們在超過合理迭代次數時中斷:
let safetyCounter = 0;
while (myCondition && safetyCounter < 1000) {
// 您的邏輯
safetyCounter++;
}
這些有幫助嗎?
正如我所說,附加到 LLM 的記憶體位於工作流程的中間。
一旦我附加了記憶體,我就在幾個程式碼節點上遇到了問題,而且某些程式碼節點位於工作流程的開始(甚至在 llm memory 節點執行之前)。
沒有記憶體,工作流程完成執行時沒有問題,但有了記憶體,同一個工作流程在程式碼節點開始出現問題
由於你沒有清楚說明,我假設這發生在 AI Agent 之後
這樣更清楚了。聽起來像是記憶體迴歸的問題
更新到最新穩定版本的 n8n 有幫助嗎?
嗨 @sherazbintahir
程式碼節點因為存在子節點而懸掛,包括在它之前執行的節點,這是任務執行器無法解析該子節點類型的問題。任何讓程式碼節點向主程序請求額外上下文的操作,例如 $('Node Name') 或 $node["Node Name"] 參考,或是 require() 外部模組,都會將執行器送回以重建工作流程。執行器無法解析的子節點類型會讓該請求保持未回答狀態,直到 300 秒後被終止。你的 n8n 容器日誌會在它停止時顯示「Unrecognized node type: …」。
將這些程式碼節點改寫為只使用 $input 和 $json,並先用 Set 節點將它們需要的任何東西從較早的節點移到主路徑上。在 2.11.3 版本上關閉執行器不是選項,N8N_RUNNERS_ENABLED 已從 2.0 版開始棄用,每個程式碼節點執行都在執行器上運行。
感謝,這會很有幫助。但我這裡感到困惑,因為我的完整工作流程(120+ 個節點)運作得很完美,沒有任何錯誤,但當我將記憶體附加到 LLM(帶有 OpenAI + 記憶體的 AI 代理節點)時,我就遇到了這個問題。
如需更多資訊,在沒有記憶體的工作流程中,我直接使用 OpenAI 節點。而且我不是在所有代碼節點上都遇到此問題,只是在少數幾個。
黃色框:我正在附加記憶體和 LLM 的地方。
紅色點:我遇到代碼節點問題的地方。大多數節點是那些我用來建立/準備要發送到儀表板的負載的節點。
嗨 @sherazbintahir
你有試過改用 PostgreSQL 來排除 SQLite 資料庫鎖定 的問題嗎?
services:
postgres:
image: postgres:16-alpine
environment:
- POSTGRES_USER=n8n_user
- POSTGRES_PASSWORD=n8n_password
- POSTGRES_DB=n8n_db
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n8n_user -d n8n_db"]
interval: 5s
timeout: 5s
retries: 5
n8n:
image: n8nio/n8n:2.11.3
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n_db
- DB_POSTGRESDB_USER=n8n_user
- DB_POSTGRESDB_PASSWORD=n8n_password
- EXECUTIONS_PROCESS=own
depends_on:
postgres:
condition: service_healthy
volumes:
postgres_data:
Hi @sherazbintahir 這不是速度慢的問題,你的 Code 節點發生了死鎖,不是忙碌。
自 v2.0 以來,所有 Code 節點都在單獨的任務運行程序進程中運行。如果腳本只使用 input/input / input/json,它會獲得精簡的負載並立即運行。但如果它使用 ('NodeName') 或 ('Node Name') 或 node['Node Name'],運行程序必須向 n8n 請求整個序列化工作流,並重新構建它,這需要解析畫布上的每個節點類型,包括子節點。附加記憶體子節點後,運行程序會遇到無法解析的類型,請求永遠不會返回,你的 Code 節點會一直等待,直到 300 秒的看門狗將其殺死。與 #20752 相同。
這也解釋了為什麼只有某些 Code 節點出現故障——運行正常的節點是那些從不超出其自身輸入範圍的節點。
你能檢查兩件事嗎?
- 附加記憶體運行它,並搜索你的日誌:
docker logs -f <n8n-container> | grep -i "unrecognized node type"
- 打開其中一個凍結的 Code 節點——它的任何地方是否包含
$('...') 或 $node[...]?
如果兩個都是肯定的,修復很簡單:在它前面放一個 Set 節點,並作為表達式傳入值(={{ $('Clean JSON').first().json.config }}——普通節點中的表達式在主進程中運行,不受影響),然後在 Code 節點中從 $input 讀取它。記憶體保持完全不變。
發佈日誌行說了什麼,我會給你節點的確切重寫。
@sherazbintahir 那個變數不是記憶體——是節點交換。沒有記憶體的話,你用的是普通的 OpenAI 節點。要附加記憶體,你得切換到 AI Agent,一個 LangChain 叢集根節點,會把子節點拉到畫布上(Chat Model、Memory、你的 search_workwell_memory 工具)。OpenAI 節點在任務運行器中解析得很好;Agent 子節點通常不行。
為什麼只有某些 Code 節點:從 v2.0 開始,所有 Code 節點都在單獨的運行器進程中執行。
- 只使用
$input / $json → 精簡負載,瞬間完成。是(你的清理/驗證節點)
- 使用
$('Node') / $node['Node'] / $items() — 運行器要求整個序列化工作流回傳,並重新構建,這意味著解析你的 120 節點畫布上的每個節點類型,包括子節點。一個無法解析的類型——請求永遠不會回傳——掛起直到 300 秒看門狗觸發。否(你的負載建構器——紅點)
注意工具子節點本身也能導致這個問題:#20752 是 postgrestool,#20132 是 Apify/Perplexity——那裡即使 Agent 從未執行也掛起了。
在 30 秒內確認——保留記憶體已附加,打樁一個凍結節點:
js
// const cfg = $('Prepare Normal Formatter Evidence').first().json;
const cfg = { test: true };
瞬間執行 → 已確認。
最佳修復方案優先:
- 將節點合併到 Code 節點中,然後讀取
$input.all()。在你的規模下最乾淨。
- 在前面設置節點,將值解析為表達式:
={{ $('Parse Extraction').first().json.score }} 普通節點中的表達式在主進程中評估,所以它們免疫。
- 跳過 Code 節點——直接在 HTTP Request 節點中使用表達式構建 JSON 主體。
在返回的項目上保留 pairedItem: { item: index },否則下游表達式會重新引入問題。在所有三種情況下,記憶體都保持附加。
沒幫助:提高 N8N_RUNNERS_TASK_TIMEOUT(等待是無限的),或 N8N_RUNNERS_ENABLED=false(在 2.x 中被忽略)。
在連接 Agent 的情況下執行時,能否貼出 docker logs -f <n8n-container> | grep -i "unrecognized" 的輸出?那會顯示是記憶體還是工具的問題。