你如何捕捉看似正常運行但實際上什麼都沒做的工作流?
我已經在 n8n 中運行客戶自動化有一段時間了,但一直遇到同樣的故障,我很想知道其他人如何處理這個問題。
工作流執行了。每個節點都是綠色的。沒有拋出任何錯誤。但零筆記錄實際上進入了系統。
通常是上游某個地方出現的問題:令牌過期、欄位被重新命名、API 改變了回應格式,或者篩選條件突然不符合任何內容。錯誤工作流永遠不會觸發,因為從系統的角度來看沒有任何問題。
真正讓我浪費時間的不是修復,而是延遲。等到有人注意到時,它已經壞了好幾天了。
所以,特別是對於那些為客戶運行工作流的人:
• 你是否檢查超出錯誤工作流以外的任何東西?
• 有人是否連接了外部服務來處理這個問題(Healthchecks.io、cron pings、自訂的心跳節點)?
• 你是否驗證記錄數量,還是只確認運行完成了?
• 或者老實說,你通常是在客戶告訴你時才發現?
最後一種情況是我想要停止的。很想聽聽什麼方法對人們來說真正有效。
嘿 @rodri.galloswork,在等待回覆時,以下是一些可能有幫助的資源:
建議的資源
自動符合您的問題。
文件:
論壇:
@ShawnWilliams、@Dan_Westness、@Niffzy - 你們之前曾幫助解決過類似的問題,能看一下嗎?
由 n8n 社群機器人自動建議。這是試行版 - 請在此分享反饋。
是的——有用的區分是執行健康度與結果健康度。我通常將其分為三項檢查:
- 執行健康度:開始/結束、持續時間、重試次數、上游狀態和執行錯誤路徑。
- 輸出健康度:預期計數窗口、新鮮度、必填欄位、結構雜湊和重複金鑰檢查。
- 接收健康度:下游記錄 ID、確認或明確的例外項目。
綠色執行但出現意外零值應該進行審查,而非視為成功。保留原始執行證據,並對連續遺漏發出警告,以免單一合法的空結果產生雜訊。
我在這裡的一個小型合成實驗室中設置了邊界:n8n Silent Success Lab | Romeo Apps
這是 RomeoApps 擁有的夾具數據,不是客戶遙測,且不使用任何認證。對於真正的工作流程,編輯後的執行、預期輸出窗口和目標確認通常足以識別第一個遺漏的檢查。
上面對執行與輸出與收據健康狀況的很好的分析。在實際的 n8n 方面,這是一個輕量級的模式,可以在沒有額外基礎設施的情況下捕捉到這個問題:
- 單獨的錯誤觸發器工作流在這裡幫不了什麼——它只在未處理的例外上觸發,而你的問題正好是沒有任何東西拋出例外的情況。
- 用IF 節點結束你的主工作流,檢查來自最後一個「真實」節點的實際項目計數(或特定字段)。如果它是 0 或不符合你的預期,將其路由到停止並錯誤節點——這會強制 n8n 將空白/錯誤的結果視為失敗,然後確實會觸發你的錯誤工作流 / 通知。
- 特別是針對「無聲數天」的問題,單獨的排程觸發器心跳工作流效果很好:每隔 N 分鐘/小時檢查一次(HTTP 請求或資料庫查詢)預期的下游記錄是否最近被建立,如果沒有就提醒你。
- 將記錄計數檢查儘可能放在靠近實際寫入節點的位置(就在 Kintone/資料庫/API 寫入之後),而不是在工作流的最後——這樣你可以在其他分支繼續使用壞數據之前捕捉到它。
對我幫助最大的模式:永遠不要讓「工作流完成而沒有錯誤」成為你唯一的成功信號——始終在允許工作流結束為綠色之前添加一個明確的斷言節點。
嗨 @rodri.galloswork
這是一個眾所周知且重要的問題。如其他人所說,你需要區分出現錯誤的工作流程和成功執行但沒有產生任何結果的工作流程。在第二種情況下,你不能只依賴內置的錯誤工作流程。
你可以在流程的末尾添加一個斷言檢查,但我更偏好在開始時進行「守門人」檢查。這樣更高效,因為如果沒有數據要處理,它會停止工作流程的其餘部分執行。
該模式很簡單:
-
在你的主查詢(例如「從數據庫取得記錄」、「HTTP 請求」)之後,添加一個 IF 節點。
-
設置 IF 節點以檢查傳入項目的數量是否等於 0。
-
真路徑是導向「失敗」的路徑。這是你可以設置某些事情發生時要做什麼的地方(例如發送 Slack 消息、建立 Jira 工單、發送電子郵件)。你可以在這裡添加「停止並出錯」節點以觸發全局錯誤工作流程。
-
假路徑是你的「成功」路徑,它繼續執行工作流程的其餘正常邏輯。
這樣,工作流程只在有數據時才會進行,如果沒有提取任何數據,你會立即收到警報。
希望這有幫助。
這個做得很扎實,尤其是關於在寫入節點後立即進行計數檢查,而不是放在最後的部分。我經常看到這個錯誤,人們檢查得太晚,不良數據已經向下游傳播了
分離的心跳工作流方法基本上就是我在圍繞這個構建時採用的方法。棘手的部分在於規模上為每個客戶端維護一個工作流,當你跨不同客戶端有15或20個自動化時,手動心跳設置開始佔用實時。這一直是驅動我構建在工作流本身之外處理它的東西的主要因素
開始的守門人很聰明,我之前沒想到這種方式。它會阻止整個鏈在空數據上運行,而不是讓它通過然後在最後檢查。肯定更有效率
不過我一直在這個模式中遇到的一個問題是,它在每個工作流程中效果很好,但無法解決「工作流程完全停止運行」的情況。比如說,如果排程觸發器本身因為某個原因停止觸發,IF 節點甚至沒有機會檢查。這就是為什麼上面的心跳層很重要,需要有外部機制來注意到工作流程變得無聲,而不僅僅是它運行時沒有數據
關於「每個客戶端一個心跳工作流程無法擴展」的部分——對我有幫助的是反轉它:不要讓每個工作流程擁有自己的監控器,而是讓每個工作流程報告到一個共享的檢查點,並在該表上運行單個監視程序。
具體來說:
-
一個微小的子工作流程 checkin,在每條管道的末尾通過「執行工作流程」調用(理想情況下應在寫入節點之後立即調用,正如 nathan3 所說)。它接受三個值:pipeline(穩定名稱)、count(實際寫入的項目數)、ok(布爾值)。它在 heartbeats 表中更新插入一行:pipeline、last_seen、last_count、last_ok。三個字段,每個工作流程只需添加一個節點,無需按客戶端監控工作流程。
-
一個 expectations 表,每條管道手動填寫一次:pipeline、max_silence_minutes、min_count。這是值得有意識地做的部分——寫下「這應該至少每小時運行一次並至少登錄 1 條記錄」是將監控從感覺轉變為檢查的原因。
-
一個每 15 分鐘觸發一次的「排程觸發」工作流程,它聯接這兩個表:如果 now - last_seen > max_silence_minutes(捕捉你提到的「觸發器完全停止激發」的情況,因為行更新的缺失本身就是信號)、last_count < min_count 或 last_ok = false,則發出警報。添加客戶端 #21 只是在 expectations 中添加一行加上一個「執行工作流程」節點,而不是新的心跳工作流程。
這種方法有兩件事對我幫助很大:
- 對於有合理空窗期的任何東西,在 N 次連續遺漏時發出警報,而不是第一次遺漏時。否則週末安靜時期會讓每個人都習慣性忽視該頻道。
- 讓監視程序本身在某個外部位置進行心跳檢測(cron ping 服務就可以)。上述所有內容都位於 n8n 內部,所以如果實例宕機,監視程序也會宕機,你會得到沉默而不是警報。這是一個外部依賴項,它覆蓋整個隊列而不是每個工作流程一個。
關於「排程是否仍在激發」:如果你是自托管,你也可以直接從 n8n REST API 讀取——GET /api/v1/executions?workflowId=...&limit=1 並將 startedAt 與預期的節奏進行比較。同樣的監視程序工作流程,受監控的工作流程中根本沒有任何工具代碼,不過你會失去「運行但未寫入任何內容」的信號,所以我會在檢查行旁邊使用它而不是代替它。
Count == 0 會捕捉到這個明顯的版本。對我們造成更大傷害的是 count > 0 但錯誤的情況:N 列著陸,assertion 通過,但它們每一列在重要的欄位中都有 null,因為上游欄位被重新命名,而你的寫入節點仍然接受了該列。這個執行緒的 IF-node-on-count 模式中沒有任何東西能捕捉到這一點,因為它檢查的是基數,而不是形狀。
修復方法是相同形狀的節點,只是斷言不同的東西:在寫入後,檢查你實際依賴的兩個或三個欄位是否非 null 且大致是正確的類型,而不是檢查項目計數是否非零。在 nathan3 已經描述的相同 IF 節點上只需要多一個條件,它能捕捉到重新命名或 API 合約變更降低資料品質而不是將其清零的失敗模式,這是我的經驗中 schema 變更實際上破壞某些東西的更常見方式。
如果你對這些執行進行計費或開票,還有一件值得構建的事情:將相同的 assertion 路由到任何決定「這次執行是否計數」的地方,而不是第二個更寬鬆的檢查。容易陷入這樣的狀態:嚴格版本會提醒你,但一個單獨的、較舊的閘門仍然是決定客戶是否被收費的因素,這兩個會隨著時間推移而無聲地偏離。
themineworks 指出的重點是我想強調的:計數是基數(cardinality),不是正確性,真正會造成損失的失敗是 N 列資料落地時,你依賴的欄位為 null,或更糟的是,該欄位存在且看起來合理但實際上錯誤。一個欄位在上游被重新命名,你的寫入節點仍然接受該列,現在你有看起來真實但卻悄悄不正確的資料。Null 和型別斷言捕捉退化為空的情況。它們不會捕捉退化為某個看似合理、非 null、型別正確,但就是錯誤的情況,因為行上沒有任何東西看起來不對。
唯一能捕捉這種情況的檢查是已知答案金絲雀(known answer canary)。與實際流量一起,推送一些你事先寫下正確輸出的合成輸入,按計畫通過實時管道端到端運行它們,並斷言輸出等於已知答案,不只是它的形狀正確。如果映射悄悄開始指向錯誤但有效的欄位,金絲雀的預期值就會停止匹配,你會在同一天得到大聲的失敗,因為你是在與事實比較而不是與合理性比較。
它也彌合了 Cam 提出的差距。一個未能報告的金絲雀本身就是警報,所以同一機制捕捉管道靜默和值悄悄出錯的情況,用一個外部檢查監看金絲雀結果,而不是每個工作流程一個心跳。在實踐中,我運行三層:寫入後立即進行計數和 null 或型別斷言以捕捉大聲的失敗、用於緩慢洩漏的容量水標,以及用於第一層結構上無法看到的看似合理但錯誤情況的計畫性已知答案金絲雀。
count > 0 但形狀錯誤的情況也是我會擔心的。
一個有用的模式是讓最終的「成功」檢查證明你關心的成品確實存在,而不只是有東西被寫入。例如:下游 ID 存在、必要的業務欄位非空、來源 ID 被保留,以及執行 ID 附加在某個你可以稍後審計的地方。
否則你最終會得到綠色的執行結果,但目標地點充滿了沒人能真正使用的記錄。
@rodri.galloswork 你提到維持每個工作流程的心跳檢測在跨客戶端 15–20 個自動化時開始佔用真實時間,這迫使你構建工作流程以外的東西。這也是我一直在研究的事情..(我是開發者,在決定是否構建之前先學習)。
上次客戶端工作流程顯示綠色但什麼都沒做時,在有人發現之前壞了多久,是你先發現還是客戶先發現?
「在工作流程外處理它」需要為你做什麼才能讓你真正信任它?
在 2.36.7 版本上發現了一個我原本以為運作方式不同的問題。
當 IF 條件停止匹配時,該分支上的節點並未被標記為跳過。它根本不在 runData 中。執行仍然返回 status: success。
因此,如果您迭代節點來尋找不良狀態,您什麼都找不到。信號是一個不存在的鍵。
重現步驟:排程觸發器、發出行的代碼節點、永遠無法匹配的 IF,以及在 true 分支上的代碼節點。最後那個節點就是丟失了。
這個討論串中的一切都會告訴你何時執行出錯。在那之前還有一個步驟是沒人提過的,它特別針對 15–20 個自動化的問題:你可以透過閱讀工作流程的 JSON,在對其中任何一個進行檢測之前,就找出你的哪些工作流程甚至有能力出現這種故障。
上面的斷言模式沒錯。但每一個都要消耗一個節點和每個工作流程一次的判斷呼籲,在 20 個跨越不同客戶的工作流程中,這正好是會吃掉時間的部分。所以有用的問題變成:哪些應該首先獲得斷言?
從檔案來就能回答這個問題。對於每個在 n8n 之外寫入內容的節點——資料庫、Sheets、CRM、Slack、任何 HTTP POST/PUT/DELETE——檢查是否存在一條從觸發器到工作流程結束的路徑,該路徑到達終點而不經過該節點。一個 IF 在假分支上沒有任何內容、一個 Switch 沒有後備選項、一個可以清空項目列表的篩選器:每一個都給你一個正常完成且不寫入任何內容的執行。這些是 CameronDWills 的簽入節點和 nathan3 的斷言發揮價值的工作流程。每個寫入都位於每個路徑上的工作流程可以等待。
手動操作每個只需幾分鐘:列出寫入、追蹤回觸發器、詢問那個執行是否仍然看起來成功。
我在 2,043 個公開 n8n 範本上執行了該檢查。13.5% 至少有一個高嚴重性的案例——一個寫入可以被跳過,同時執行仍然報告成功。範本是經過精心策劃和打磨的,所以我會將其解讀為下限而不是平均值。
既然你在實際運用中,我有一個反問:當客戶工作流程沉寂時,延遲通常是因為不知道出了什麼問題,還是不知道在 20 個中應該先開哪一個?我一直假設是後者,我想知道我是否理解錯了。
披露:我製作了一個免費頁面來執行此檢查——貼上工作流程 JSON,它會列出可以跳過的寫入。無需登入,在你的瀏覽器中解析,所以 JSON 永遠不會離開該頁面:https://stillrunning.dev。如果你不想在任何地方貼上內容,我很樂意在這裡走一遍工作流程。
我認為你基本上已經涵蓋了所有情況,但這是我的做法。
我有一個系統化的錯誤處理協議
- 設定錯誤工作流程 → 這是萬一一切都失敗時的最後手段,應該執行以下操作:
- 記錄錯誤
- 通知相關人員或只通知你
- (可選但仍然有用) 如果是 webhook 工作流程,你可以簡單地將有效負載附加到你的錯誤資料庫,並設置一個按鈕將其重新發送到 webhook;這樣可以節省你的時間,不必前往執行紀錄、開啟工作流程等等。它從那裡重新運行工作流程,前提是你有冪等性鑰匙,且這是一個暫時性故障。
- 使用良好的冪等性鑰匙
- 工作流程級別錯誤
- 設定有效負載驗證系統;這應該能解決大多數空白資料的問題。
- 設定初始有效負載驗證
- 在寫入操作前設定最終有效負載驗證
- 絕不要使用篩選器;相反,使用 IF 節點,進行嚴格的條件驗證,並為不符合這些條件的所有情況設定停止和錯誤節點路徑
這將允許你從一開始就確保非常嚴格的協議;一切不符合這些條件的內容都會被拋出為錯誤。你可以主動管理流程,並隨著時間的推移擴展條件。
- 節點級別錯誤
- 禁用失敗時繼續
- 使用失敗時重試
- 在某些特定情況下(雖然非常罕見),使用錯誤路徑。
- 欄位級別驗證
- 在資料到達時進行處理、轉換或清理(取決於到達的資料)
- 在需要的地方使用後備值:null、undefined 等
我通常會有一個監控資料庫,其中分配了一個狀態;你可以將其作為你處理的資料的一部分(工作流程流程導致潛在客戶,而潛在客戶已經有狀態)
或者你可以手動設定一個,特別是如果你試圖主動解決這些錯誤,方法是在第一個有效負載驗證後用已啟動狀態附加運行,並在最後驗證狀態後更新狀態。(在我看來,這對於 99% 的用例來說顯然是多此一舉)
還有一些其他有用的做法,但坦白說,這涵蓋了大部分內容。
最重要的是,使用系統化協議。
總結
在每個層級強制實施嚴格規則
一切不符合你想要的內容
確保你得到通知,並且可以快速調查
如果它不是錯誤,而是要處理的新資料案例,請增加條件
@CameronDWills 的反向版本是正確的形狀。我想補充的一件事是關於它所依賴的表格。
這個討論串中的每個模式——簽入節點、斷言、金絲雀——都需要工作流程配合。你添加一個節點,或者你寫下一個預期。當你構建這個東西時,這很好。但在真正有害的兩種情況下,它就成了問題:你繼承的工作流程,以及客戶端實例,你沒有自由在了解哪些管道重要之前編輯 20 個管道。
有一個信號你可以從外部獲得,而無需接觸任何東西。executions 端點為你提供每個工作流程,每次運行何時開始以及它如何結束。從那段歷史中可以得出兩件事:
頻率。 對工作流程的執行進行排序並取中位數間隔。那就是預期——你不用為每個管道手寫 max_silence_minutes,這在 20 個跨客戶端的工作流程中等同於以新的方式出現的相同擴展問題。一個在一個月內每小時運行一次但六個月內沒有運行過的工作流程是@Cam 提出的「觸發停止觸發」情況,在沒有心跳節點的情況下捕捉到。
相對於自身基線的錯誤率,而不是固定閾值。 一個始終失敗 2% 的工作流程不是新聞。一個從 2% 上升到 30% 的才是。在我的經驗中,跨異構工作流程的固定閾值是人們在第二個月開始靜音這些警報的原因。
它不會替代斷言。API 無法告訴你一次運行是否寫入了 null——只是它運行了以及它返回了什麼。外到內告訴你一個工作流程變得安靜或生病了;內到外告訴你它在說謊。你希望兩者兼備,但只有一個適用於你還沒有打開過的工作流程。
(注意:API 不會暴露憑證過期,所以你從事後的 401 捕捉到過期的令牌,而不是提前捕捉。)
我認為這個串討中埋藏著一個值得分開討論的區分,因為修復方式不同。
上面幾乎所有的內容都是關於曾經有效但悄悄停止工作的工作流程——令牌過期、欄位被重新命名、回應結構改變。計數斷言和心跳工作流程是解決這個問題的正確方法。
這個問題的另一半是從一開始就從未工作過的工作流程,但從第一次執行就報告了成功。
我最近正確執行了五個我自己的工作流程——針對一台本地伺服器代理 API,記錄每個傳出請求的內容。所有五個都是破損的,但全部都顯示綠色:
-
一個 HTTP 請求節點(typeVersion 4.2, contentType json),其中負載位在 body 參數中而不是 jsonBody。該節點讀取 jsonBody,所以實際發出的是 {"":""} 。端點回應 200。每個節點都是綠色。
-
提示文本存儲在 Set 節點中,沒有前導 =,所以 n8n 從未評估它。模型收到了字面字元 {{ $json.article_text }} 並仍然回答了,無中生有地產生了一個完全看似合理的回應。
-
一個解析步驟將 API 回應展開到它正在豐富的項目上,覆蓋了原始欄位。下游的所有內容都在錯誤的對象上愉快地執行。
這些都沒有拋出異常。項目計數檢查也捕捉不到它們,因為計數都是正確的——每個步驟都是一個項目進來,一個項目出去。問題在於發送內容的正確性,而執行檢視中沒有任何東西能顯示這一點,除非你打開節點並讀取它。
唯一捕捉到它們的方式是將每個整合指向一台記錄請求內容的本地伺服器,執行一次工作流程,然後讀取日誌。二十分鐘的設置時間,它在我指向它的每個工作流程中都發現了問題。
所以除了「計數是否符合我的期望」之外,我還會補充第二個問題:「我是否真正查看過它發送的內容?」對於任何已在生產環境中的東西,上面描述的斷言是答案。對於任何新的東西,在信任它之前,讀取一次位元組。
@enzosoftware 的貼文是我會以此為基礎的,因為「我真的看過這傳送的內容嗎?」是正確的問題,而將整合指向一個記錄請求本體的本機伺服器是回答問題的最便宜方式。這裡的情況相同,它從未乾淨過。
之後還有一個問題,我認為這個問題在執行緒中還沒有出現過:一旦你發現了問題並寫了修復方案,你如何知道修復方案有效?
預設答案是部署並監視。這使得生產環境成為測試台,用於根據定義不會自行宣布的故障類別,所以「自星期二以來沒有警報」與「仍然損壞,仍然無聲」無法區分。Miguel_Ruilope 描述的節奏和錯誤率基準線最終會浮現它,但最終承載了很多重量。
對我來說可行的是保留它損壞時的記錄執行、實際請求和回應本體而不是摘要,以及針對該精確記錄回放候選修復,並阻止出口。兩個特性完成工作。
密閉網路:如果回放可以到達即時 API,你測試的是今天的 API,不是損壞你的那個,綠色結果毫無意義。
原始位元組而不是摘要:這整個故障類別就是形狀,上面的空 JSON 本體例子正是摘要日誌拋棄的。
然後問題變得足夠狹窄以實際回答:這個修復是否會將該特定記錄的故障轉變為正確輸出,是或否。遠比「這個工作流程是否健康」更容易確定。
老實說它的限制是這只適用於你已經記錄的故障。對於任何尚未捕捉到的東西,@ali.alsamraay 對工作流程 JSON 的靜態閱讀,以及在信任新工作流程之前讀取一次位元組,嚴格來說更好,因為兩者都不需要故障首先發生。由外向內、由內向外和回放回答三個不同的問題,我認為其中任何一個都不能替代其他的。
披露,精神與 ali 的相同:我建造了一個執行回放和驗證部分的工具,其主要設計規則是當它無法證明修復有效時,它拒絕聲稱修復有效。它是免費的,目前還沒有使用者,所以請將其視為值得竊取的方法,而不是建議。密閉回放的想法比我的實現更有價值。
密封重播且出口被阻止是正確的形式,原始位元組規則是我會強調的部分。空主體情況的摘要日誌看起來與健康的日誌相同,所以如果記錄拋棄它,重播就無法證明任何事情。
不過我會補充一半,它位於你的重播變綠的位置之後。
我修復了五個工作流程中的九個缺陷,針對本地日誌伺服器重新執行每一個,並將捕獲的主體與我的預期進行了比對。全部九個都回來正確了。修復是真實的。
其中一個工作流程是作為可下載文件出售的。任何購買過它的人仍然會得到破損的版本,因為我驗證過的東西和被交付出去的東西已經悄悄地漂移了。我只是通過像客戶那樣下載我自己的產品並檢查位元組與我建立的文件是否相符才發現的。它們不匹配。
所以重播回答了「這個修復是否將那個記錄的失敗轉變為正確的輸出」。它無法回答「修復是否在任何人實際收到的製品中」。對於你自己運行的工作流程,這是同一個問題。一旦有出口、部署步驟、模板導入或某人下載的文件,它們就會分離,間隙的寧靜方式正好就像原始缺陷一樣。
關閉它的檢查很乏味。以接收者獲取的方式獲取製品,而不是你建立的方式,並從中進行重播。如果它是文件,對其進行雜湊。如果它是導入,將其導入乾淨的實例並針對另一端的任何結果執行密封重播。
你描述的失敗類別是綠色並不意味著工作。這是相同類別再往外一步。修復並不意味著已發布。
CameronDWills 的預期表格是我會著手改進的部分,因為寫下「這應該至少每小時運行一次,至少產生一條記錄」正是將監控從直覺轉變為檢查的方式。這也是會逐漸老化的部分,而我不認為這個討論串有涵蓋它在第二個月會發生什麼。
min_count 隨著量變而過時是已知的一半,上面討論串中的滾動中位數建議可以處理它。咬我的是一旦你超越計數,開始斷言特定值必須出現時會發生什麼。那個清單變成了一個維護對象,而沒有東西維護它。
一位運行銀行對帳單提取的操作員告訴我他的是如何結束的。他的一個命名值在上游重新命名了。檢查每天早上抱怨,他就停止讀它。它仍在運行且仍然正確。它已經變成了噪音,這比沒有還糟,因為工作流程現在沒人監看,但他以為它在被監看。
修復它的做法是拒絕把「預期值缺失」當作一個條件。它是三個,而它們需要不同的輸出。
最近運行中沒見過:已重新命名或已停用。不是警報,是指示。更新清單,並明確表示它會一直重複,直到有人動手。
在少數運行中看到:真實,但不是每次運行。月度線出現在每小時的提取中。它從來不應該在每次運行清單中,監控它意味著在幾乎每次運行中都發出警報。
持續看到然後消失:實際的警報,也是這三個中唯一值得醒來的。
相關的是,它也適用於監看視窗:檢查應該能夠拒絕回答。一個每小時工作流程的三十次執行就是三十小時的證據。詢問那份資料季度發票是否送達,誠實的輸出是「未涵蓋」,不是「否」。EXECUTIONS_DATA_MAX_AGE 靜靜地縮短了那個視窗,而被刪除的運行不是缺席的證據,它根本不是任何東西的證據。
上面的帖子把它表述為固定不等於已發布。這在不同的方向上是同樣的形狀:運行不等於已讀。