上一篇處理的是 Sandbox Adaptive Execution。
遇到 OOM 時,不是直接換更大的 sandbox,而是先調整 execution strategy:
OOM
→ Rewrite
→ Retry
但如果 rewrite 之後還是超過 memory limit 呢?
這時才需要 scale up。
這次讓 Agent 在 sandbox 裡:
Generate 16,000 random 2-D points, run Ward hierarchical clustering on all of them, cut the tree into 5 clusters, and return the cluster sizes.
一開始拿到的是 1 GB sandbox。
Agent 寫好 clustering.py 後執行,第一次 OOM:
Agent 沒有馬上換 bigger sandbox,而是先 rewrite code。
第二次執行還是 OOM:
也就是:
1 GB Sandbox
→ OOM
→ Rewrite
→ OOM again
兩次 execution 都已經碰到 1 GB memory limit,這時才進入 scale up。
這裡不是直接 resize 原本的 sandbox。
目前這個 Daytona setup 上,我用的是 replace:
1 GB Sandbox
↓
Create 4 GB Sandbox
↓
Install Packages
↓
Copy Work Folder
↓
Switch
↓
Delete Old Sandbox
↓
Retry
實際 timeline 可以直接看到整個過程:

從第二次 OOM 開始:
這次 work folder 只有 6 KB,主要時間其實花在建立新的 sandbox 和準備 environment。
切換完成後,conversation 開始使用新的 4 GB sandbox,舊的 1 GB sandbox 才會被刪掉。
接著原本失敗的 code step 在新的 sandbox 上重新執行:

這次成功了:
最後 Agent 正常完成 clustering,回傳 5 個 cluster 的大小。
完整流程就是:
1 GB
→ OOM
→ Rewrite
→ OOM again
→ Move to 4 GB
→ Retry
→ Success
這也是前面把 Conversation 和 Sandbox 分開的原因。
對 Agent 來說,它做的還是:
execute("python3 /home/daytona/clustering.py")
但底下實際使用的 execution resource 可以從:
Conversation
→ 1 GB Sandbox
切成:
Conversation
→ 4 GB Sandbox
Agent 不需要自己處理 create、copy、switch、delete。
這些都是 sandbox layer 的工作。
這個 case 也剛好接回 Day 20。
Day 20 的 recovery path 是:
OOM
→ Understand the bottleneck
→ Rewrite
→ Retry
因為很多 OOM 可以透過 execution strategy 解決。
但這次 rewrite 之後仍然用了 1013 MB / 1024 MB,第二次一樣被 kill。
這時才往下一層走:
Rewrite still fails
→ Bigger Sandbox
也就是 scale up 是 recovery path 的下一步,不是看到 OOM 的第一個反應。
Replace 還有一個 capacity 問題。
新的 sandbox ready 之前,舊的不能先刪掉。
所以 migration 中間會短暫同時存在:
Old Sandbox 1 GB
New Sandbox 4 GB
單一 conversation 在這個階段暫時需要 5 GB memory capacity。
因此 scheduler 在建立 bigger sandbox 前,不只要確認還有沒有 sandbox slot,也要確認 total memory budget 放不放得下。
這也接回 Day 19:
Sandbox scheduling 不能只算 sandbox 數量,也要算 memory。
Load page 上可以更直接看到這次 execution 的差異。

Conversation 3 前兩次 execution:
step 1
→ 992 MB
→ OOM
rewrite 1
→ 1013 MB
→ OOM
換到 4 GB sandbox 後:
step 3
→ 2118 MB
→ Success
這也確認了這次不是單純「差一點點 memory」。
成功執行實際用了超過 2 GB,原本的 1 GB sandbox 確實不夠。
最直接的做法看起來會是:
1 GB
→ resize
→ 4 GB
但目前這個 Daytona account / API setup 沒有直接對 running sandbox 做 resize。
所以目前採用:
Create Bigger
→ Copy
→ Switch
→ Delete Old
因為 Agent 操作的是 LazySandbox,上層不需要跟著 provider lifecycle 改變。
Sandbox 換了,但 conversation 還是同一個 conversation。
這次整個 conversation 大致可以分成:
1 GB Sandbox ~22s
Moving ~23s
4 GB Sandbox ~18s
光 moving 就花了大約 23 秒。
所以 bigger sandbox 不適合變成每次 OOM 的預設解法。
其中比較明顯可以再優化的是 environment preparation。
這次新的 sandbox 還需要重新安裝:
pyarrow
polars
plotly
duckdb
scikit-learn
如果之後改成 prebuilt snapshot,常用 packages 已經準備好,就可以少掉這段 startup cost。
到這裡,execution recovery path 變成:
Execute
↓
OOM
↓
Rewrite Execution Strategy
↓
Still OOM
↓
Create Bigger Sandbox
↓
Move Working State
↓
Retry
Day 20 處理的是 code 怎麼調整。
這篇處理的是 code 調整還不夠時,Sandbox 怎麼跟著 workload scale up。