fix(engine): 等待搬回引擎——WASI 沙箱裡沒有「不花 CPU 地等」這種東西(Arcrun#101)
leo 在 youlin stage 實測(只有 input >> wait 兩個節點): ms=3000 → 38.9s 後 503(1102) / ms=20000 → 34.0s / ms=30000 → 34.9s / 寫死 3000 → 34.8s 四個值同一種死法、與 ms 無關 ⇒ 病不是「等待很貴」,是「等待從來沒成功過」。 修法:wait 移進 BUILTIN_COMPONENTS,由引擎 await 一個 timer。 只花 wall-clock、不記 CPU ⇒ 等 30 秒與等 3 秒同價(皆 ≈0)。 I/O 契約沿用 component.contract.yaml,既有 workflow 的 wait 節點定義不必改。 🔴 誠實標明:原本註解斷言「Workers 時鐘在同步執行期間凍結,所以自旋永不結束」。 寫測試去證,反而被打臉——workerd 裡自旋 2553 圈後 Date.now() 就前進了。 那條假斷言已刪除(不是改鬆),完整機制降級為推測。修法不依賴它: 純 WASI 沙箱本來就沒有睡覺這個手段,會等的只有宿主。 實測: npx vitest run tests/wait-builtin.test.ts → 12 passed (12) npx vitest run(全套) → 386 passed / 14 failed (14 = 動工前的既有紅燈數,未新增) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,23 @@
|
||||
// wait — 等待指定毫秒數後繼續(最多 30 秒)
|
||||
// 注意:TinyGo/WASM 環境中 time.Sleep 可能不可用,改用 busy-wait 模擬
|
||||
//
|
||||
// ⚠️ 已由引擎接手,這份 WASM 在 Cloudflare Workers 上跑不動(Arcrun#101,2026-08-12)。
|
||||
// 現行實作在 cypher-executor/src/lib/constants.ts 的 BUILTIN_COMPONENTS['wait'],
|
||||
// component-loader step 1 先命中,這顆 wasm 不會再被工作流呼叫到。
|
||||
//
|
||||
// 為什麼跑不動(不是「比較慢」,是「永遠不會結束」):
|
||||
// 下面的 time.Sleep 在 TinyGo 走 WASI poll_oneoff,而 component worker 的 WASI shim
|
||||
// 把 poll_oneoff 實作成 ENOSYS ⇒ TinyGo 排程器退化成迴圈重讀 clock_time_get 自旋;
|
||||
// Workers 的時鐘在無 I/O 的同步執行期間是凍結的 ⇒ 結束條件永遠不成立 ⇒ 一路燒到
|
||||
// CPU 上限被砍(error 1102)。leo 實測 ms=3000/20000/30000 全在 ~35 秒後 503,
|
||||
// 死法與 ms 無關 —— 這正是「迴圈沒結束」而非「等待很貴」的證據。
|
||||
//
|
||||
// 原本的舊註解寫「改用 busy-wait 模擬」是錯的:這個檔從來沒有 busy-wait,
|
||||
// 一直是 time.Sleep。那句話誤導了後來每一個讀這個檔的人。
|
||||
//
|
||||
// 本次刻意不改行為、只改註解:手邊沒有 TinyGo 工具鏈,改了 main.go 卻沒重編,
|
||||
// 會讓 repo 內已 commit 的 .component-builds/wait/component.wasm 與原始碼漂移
|
||||
// (rule 05「WASM 來源」:那份 wasm 是 self-host 用戶的部署來源)。
|
||||
// 要退役這顆零件(刪目錄/下架 wait.arcrun.dev)是另一個決定,需人拍板。
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
Reference in New Issue
Block a user