執行轉換
Graft.transition 協調一個受管理 fork 的執行單元替換。受管理 fork
註冊執行驅動,並在換代時保留契約服務物件。使用工件的 Remote 外掛支援直接 Worker 和子行程;一般模組部署與 runner 目標回傳
Aborted(UnsupportedTarget)。
啟動受管理 Remote 外掛
Section titled “啟動受管理 Remote 外掛”import { Schema } from "effect"
import * as Remote from "@graftland/plugin-remote"
declare const contract: Remote.Contract.Contract<typeof Schema.String>declare const artifact: Remote.Artifact.Artifact
export const integration = Remote.plugin(contract, { instance: "forecasts", artifact, contractModule: "@acme/integration-contract", target: { _tag: "Worker" }, maxInFlight: 16, policy: { probes: ["health"] },})將業務輸入傳給 Graft.plugin(integration, input)。子行程使用
{ _tag: "Local" }。宿主執行環境提供檔案系統、路徑、安全亂數和子行程服務。受管理 Remote 契約支援一元操作,僅允許注入可選的主機能力代理。透過服務圖解析的宿主相依服務與外掛自動重試尚不支援。使用模組位置的
Remote.plugin 選項仍採用一般重新啟動行為。
Loader 將項目 id 綁定為實例名稱。嵌入式註冊必須提供
instance;空名稱、衝突或重複名稱會在啟動單元前失敗。target
接受該名稱或數字 fork id。名稱在整個執行環境中唯一。
import { Graft } from "@graftland/graft"import * as Remote from "@graftland/plugin-remote"
declare const deployment: Remote.CandidateOptions
export const request = Graft.transition({ target: "forecasts", candidate: Remote.candidate(deployment), policy: { total: "5 minutes", drain: "5 seconds", terminate: "5 seconds", probes: ["health"], },})Remote.candidate
建構一個惰性的候選描述,包含已擷取的工件、契約模組、直接執行目標和輸入。它會複製並凍結部署資料,包括巢狀 JSON 輸入和目標選項,呼叫者後續修改不會改變保留的復原輸入。它既不驗證也不啟動工件。擷取和驗證
仍須明確執行;驅動在每次啟動單元前驗證擷取內容,復原時也會驗證。
| 入場規則 | 結果 |
|---|---|
| 已有轉換正在執行,包括試運行期 | Aborted(Busy);請求不會排隊。 |
| 目標 fork 正在關閉 | 分配單元前回傳 Aborted(Closing)。 |
| 目標沒有相符的已註冊驅動 | 分配單元前回傳 Aborted(UnsupportedTarget)。 |
| 轉換後的截止時長不是有限正數,或總預算不足以預留復原時間 | Aborted(InvalidPolicy);允許零試運行時長。 |
| 之前的轉換尚未確認單元終止 | 回傳 Aborted(Stuck),直到執行環境被釋放。遲到的退出證據不會重新開放入場。 |
| 呼叫者在入場後取消等待 | fork 負責完成轉換和復原;取消等待不會取消轉換。 |
| 結局 | 含義 |
|---|---|
Accepted |
候選已服務,並已觀察到舊單元退出。 |
Aborted |
入場失敗,或候選在切換前失敗且已確認終止。拒絕候選後保留舊路由;釋放取消回傳 Aborted(Closing) 並關閉路由。 |
Recovered |
確認候選和舊單元均已終止,再以舊工件啟動新的服務嘗試並就緒。也適用於拒絕候選時舊嘗試已經失敗的情況。 |
RecoveryFailed |
復原失敗,或內部協調器缺陷以 CoordinatorDefect 原因結束轉換;所有需要清理的單元均已確認終止。呼叫回傳 Unavailable。 |
Stuck |
無法確認必要的終止。呼叫回傳 Unavailable,後續轉換被阻止。 |
Transition.Outcome 提供帶標籤的建構函式和
$match。結局附帶階段和證據,包括完整失敗 cause、截止情況和觀察到的退出。終止命令、傳輸中斷或作用域關閉都不算退出證據。停止或排空逾時後,只要確認終止,仍可回傳
Accepted;這些失敗會保留在證據中。
直接單元證據區分 Exited 和
NotStarted:後者證明啟動已被阻止或已結束,且從未產生執行單元。傳輸中斷或終止命令收到回應都不能代替退出證據。
釋放會先關閉入場,再取消已入場的轉換。結局保留被中斷的階段、嘗試和已有證據。確認清理後回傳
Aborted(Closing);只有缺少必要退出證據才回傳
Stuck。協調器缺陷保留 cause,不會被歸類為終止失敗。確認執行單元退出不會掩蓋宿主清理失敗:Fork.dispose
獨立等待宿主釋放,並將失敗合併到
CleanupError,即使取消恰好發生在執行單元退出之後。重複終止會等待同一次宿主釋放;確認退出不會跳過它。
策略時長接受 Duration.Input,例如 "5 seconds"、Duration.seconds(5)
或毫秒數。轉換後的截止時長須為有限正數;試運行可為零。
| 欄位 | 限制 | 預設值 |
|---|---|---|
total |
整個轉換,包括終止和復原 | 5 分鐘 |
startup |
每次分配、啟動、描述、服務和就緒操作 | 30 秒 |
probe |
每個請求的探測 | 5 秒 |
trial |
切換後觀察候選 | 零 |
drain、stop、terminate |
呼叫、正常停止,以及每次退出或宿主釋放等待 | 各 5 秒 |
probes |
切換前和復原期間請求的探測名稱 | 空 |
每個階段的等待都受剩餘總預算限制。準備和試運行預留
5 × startup + probes.length × probe + drain + stop + 6 × terminate
給清理和復原。清理保留 5 × startup + probes.length × probe + 2 × terminate
的復原預算。復原在成功或需要清理之前保留兩次終止等待。總預算必須大於初始預留,否則入場回傳
Aborted(InvalidPolicy)。切換前,驅動須宣告可安全重疊執行,並提供所有需要的
name@version。
門面在呼叫的 Effect 執行時選擇服務嘗試,即使該 Effect 是之前建構的。選擇和入場與切換保持原子性。已入場的呼叫固定在該嘗試上。新呼叫進入新嘗試;舊呼叫完成、被取消,或在排空預算耗盡、舊單元退出後結束。單元終止提供清理證據;僅收到 RPC 回應無法證明伺服端請求作用域已清理。
maxInFlight
限制每個嘗試的已入場呼叫數。核心註冊預設為 256;Remote 預設為 16,接受 1–16。超額呼叫在入場前以
AdmissionRejected 拒絕,不排隊。Remote 透過 RpcClientError
回報協調器呼叫失敗,原始錯誤保留在 reason 的 cause 中。取消呼叫會釋放入場名額。
Fork.generations
觀察啟動、服務、排空、已終止和卡住的單元代。保留活動和卡住的單元代,以及最近 32 個已終止摘要;摘要包含候選身分,不含部署酬載。未受管理的 fork 回傳空清單。Fork.generationEvents
向目前訂閱者發布包含部署資料的完整代變更,不提供重播。緩衝區保留 64 個事件;慢訂閱者可能錯過較早的事件。需要持久稽核歷史時,應在 fork 外保存事件。復原會從固定的舊工件和輸入分配新的單元和服務嘗試,不重用失敗的嘗試。直接單元在停止後嘗試正常退出;停止逾時則強制終止。外部執行環境相依套件不會被擷取或固定版本。
import { Plugin, Transition } from "@graftland/graft"
declare const driver: Transition.Driverdeclare const registration: Transition.Registration
export const integration = Plugin.make({ name: "example/integration", apply: () => Transition.registerDriver(driver, registration),})註冊歸屬於目前 fork 的作用域。門面的 provision 和服務物件屬於該 fork,不屬於任何單元的服務作用域。
Transition.facade
只建構一次服務物件,並為其方法提供呼叫函式。協調器負責就緒、探測、切換、排空和復原。驅動只提供生命週期操作、私有服務上下文以及可獨立觀察的退出,不能更改路由。
自訂驅動必須在註冊或轉換入場前建構不可變候選快照,包含復原所需的每個巢狀部署值。核心保留該快照,無法複製任意驅動資源。
Driver.allocate
使用該嘗試的作用域來管理分配租約。分配失敗或確認回收後,協調器關閉該作用域,即使從未執行
Unit.start。重疊嘗試擁有獨立作用域。
分配必須是惰性的:外部執行只能在 Unit.start
中開始。終止已分配的單元必須阻止後續啟動並回報
NotStarted。終止與啟動競爭時,必須等待明確的產生或退出證據。驅動操作必須支援安全取消;無回應的操作仍歸屬於 fork,直到 fork 釋放。提供獨立且可重複觀察的
failure 和 exited。描述實作自身的操作身分,以一般外掛 apply
作為服務主體。受管理註冊暫不支援透過服務圖解析的宿主依賴和外掛自動重試;允許使用執行環境服務。狀態轉移、通用準備、串流門面、runner 轉換和多 fork 轉換尚未實作。
| 路徑 | 受管理時的行為 |
|---|---|
Fork.update、Fork.restart |
更改 fork 或其受管理後代之前,以 ManagedFork 失敗。 |
Graft.replace |
更改別名或設定描述之前,以 ReplacementConflict 失敗,原因為 ManagedFork。 |
| Loader | 樹中存在受管理 fork 時,在呼叫儲存修改之前拒絕編輯、重新整理和重試。 |
| HMR | 執行環境存在受管理 fork 時,在準備重載之前回傳 Skipped,原因為 managed-fork。 |
擴充工具可用 Transition.withUnmanaged
在外部寫入期間持有繞過入場權。寫入期間,驅動註冊會失敗。Transition.assertUnmanaged
只是唯讀預檢,不會在後續工作期間持有入場權。仍可明確釋放 fork。