程式碼節點凍結

代碼節點凍結

描述問題/錯誤/問題

我的工作流程運作完美,但當我將記憶體附加到 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.contentitem.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 節點出現故障——運行正常的節點是那些從不超出其自身輸入範圍的節點。

你能檢查兩件事嗎?

  1. 附加記憶體運行它,並搜索你的日誌:
   docker logs -f <n8n-container> | grep -i "unrecognized node type"
  1. 打開其中一個凍結的 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 秒看門狗觸發。否(你的負載建構器——紅點)

注意工具子節點本身也能導致這個問題:#20752postgrestool#20132 是 Apify/Perplexity——那裡即使 Agent 從未執行也掛起了。

在 30 秒內確認——保留記憶體已附加,打樁一個凍結節點:

js

// const cfg = $('Prepare Normal Formatter Evidence').first().json;
const cfg = { test: true };

瞬間執行 → 已確認。

最佳修復方案優先:

  1. 將節點合併到 Code 節點中,然後讀取 $input.all()。在你的規模下最乾淨。
  2. 在前面設置節點,將值解析為表達式:={{ $('Parse Extraction').first().json.score }} 普通節點中的表達式在主進程中評估,所以它們免疫。
  3. 跳過 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" 的輸出?那會顯示是記憶體還是工具的問題。