FAkka.Proc.Supervisor
1.564.101.201
dotnet add package FAkka.Proc.Supervisor --version 1.564.101.201
NuGet\Install-Package FAkka.Proc.Supervisor -Version 1.564.101.201
<PackageReference Include="FAkka.Proc.Supervisor" Version="1.564.101.201" />
<PackageVersion Include="FAkka.Proc.Supervisor" Version="1.564.101.201" />
<PackageReference Include="FAkka.Proc.Supervisor" />
paket add FAkka.Proc.Supervisor --version 1.564.101.201
#r "nuget: FAkka.Proc.Supervisor, 1.564.101.201"
#:package FAkka.Proc.Supervisor@1.564.101.201
#addin nuget:?package=FAkka.Proc.Supervisor&version=1.564.101.201
#tool nuget:?package=FAkka.Proc.Supervisor&version=1.564.101.201
Akka.Proc.Supervisor
Akka.Proc.Supervisor 是一個基於 Akka.NET 的進程管理與監督服務,專門用來管理與調度外部進程 (Processes),特別是 F# Interactive (FSI) 節點。它結合了 Akka Cluster Sharding、Quartz.NET 排程與 Suave HTTP REST API,提供了一個高可用、可擴展的分散式進程執行與監控環境。
系統架構
系統主要分為兩種執行模式 (Mode):Supervisor (監督者) 與 ProcNode (進程節點)。
1. Supervisor (監督者模式)
負責管理所有衍生的子進程。核心元件包括:
- ProcRegistryActor: 維護所有子進程的狀態快照 (Snapshot),提供進程列表與狀態查詢。
- ProcSupervisorActor: 作為對外的唯一入口,將指令路由至對應的 Sharding Region 或 Registry。
- ProcNodeActor: 這是透過 Akka Cluster Sharding 動態建立的 Actor,每一個
ProcNodeActor負責一對一管理一個底層的作業系統進程 (OS Process)。它負責:- 啟動與停止
System.Diagnostics.Process。 - 監控 stdout / stderr 輸出。
- 定期 Probe (探測) 子節點的 FSI 服務健康狀態(支援 Quartz Cron 或固定間隔)。
- 若探測失敗超過閥值 (
probeFailureThreshold) 或進程意外崩潰,會自動重啟進程。 - 作為橋樑,將 FSI 相關的指令 (如
ForwardMessage) 轉發給子節點的 FSI Supervisor。
- 啟動與停止
- REST API (ProcRest): 提供 HTTP 介面供外部控制進程的啟動、停止與訊息發送。
2. ProcNode (進程節點模式)
被 Supervisor 啟動的子進程。通常是執行同樣的執行檔,但加上 --mode procnode 參數。
- 啟動時會加入 Akka Cluster。
- 啟動內建的
Akka.FSI.Supervisor(F# 互動環境監督者)。 - 啟動成功後,會透過 Actor Selection 回傳
ProcNodeReady訊息給 Supervisor,告知自身的 PID 與 FSI Actor 路徑。
REST API 介面
Supervisor 提供了一系列基於 Suave 的 HTTP API (預設 Port 為 6001)。
系統與叢集資訊
GET /health或GET /healthcheck: 系統健康檢查。GET /api/cluster/info: 取得叢集狀態與角色。POST /api/cluster/shutdown: 優雅地關閉所有子進程並關閉 Supervisor。
進程管理
GET /api/proc/nodes: 取得所有進程的狀態清單 (快照)。POST /api/proc/nodes/start-default: 啟動一個預設的 ProcNode (執行自身並帶入--mode procnode等參數)。- Payload (Optional):
{ "procId": "自訂ID" }
- Payload (Optional):
POST /api/proc/nodes/start: 啟動一個自訂進程。- Payload:
{ "procId": "...", "fileName": "...", "args": [...], "workingDir": "...", "probeMessage": "...", "probeCron": "...", "probeIntervalMs": 15000 }
- Payload:
POST /api/proc/nodes/{procId}/stop: 停止指定的進程。- Payload (Optional):
{ "force": true }
- Payload (Optional):
POST /api/proc/nodes/clean-stopped: 清除 Registry 中已停止進程的紀錄。
FSI 互動 (透過 Probe 與 Send)
GET /api/proc/nodes/{procId}/probe: 取得進程目前的探測設定。POST /api/proc/nodes/{procId}/probe: 更新探測設定。- Payload:
{ "probeMessage": "...", "probeCron": "...", "probeIntervalMs": 15000 }
- Payload:
GET /api/proc/nodes/{procId}/sessions: 取得該進程內 FSI Supervisor 的所有會話 (Sessions) 列表。POST /api/proc/nodes/{procId}/send: 傳送指令到目標進程的 FSI Supervisor。- Payload:
{ "message": "執行字串", "timeoutMs": 30000 }
- Payload:
Message 格式 (傳送至 FSI)
透過 /api/proc/nodes/{procId}/send 傳送的 message 會由 ProcMessageParser 解析。支援的字串指令包含:
- 執行 F# 程式碼:
exec --session <sessionName> --code "<fsharp code>" [--refs ...] [--loads ...] - 取得 Session 資訊:
getsession <sessionName> - 列出所有 Sessions:
listsessions [--all true|false] - 建立 Checkpoint:
checkpoint --session <sessionName> [--id <id>] [--comment <text>] - Fork Session:
fork --fromsession <old> --newsession <new> [--checkpointid <id>] - Join Sessions:
join --parentsession <parent> --childsessions <child1> <child2> [--reducer <code>]
啟動參數 (CLI Arguments)
Supervisor 模式啟動範例:
./Akka.Proc.Supervisor --mode supervisor --systemname "proc-system" --host 127.0.0.1 --port 5001 --spawndefault
這會啟動 Supervisor,並自動衍生一個預設的 ProcNode。
注意:
- 若你是直接執行
.dll,請使用dotnet exec --runtimeconfig ... --depsfile ... Akka.Proc.Supervisor.dll ...,不要只寫dotnet Akka.Proc.Supervisor.dll。--spawndefault依賴 bootstrap procnode;目前已驗證可用的最小 smoke 會顯式設定--host/--port/--webhost/--webport。POST /api/proc/nodes/{procId}/send目前仍有一個已知限制,見文末「已知問題」。- 若你在 deployed 環境排查
fsi-supervisor,不要直接拿既有 bootstrap/stale proc 的fsiSupervisorPath下結論。較可靠的順序是:
- 先 direct ask
proc-supervisor GetVesion- 再
GetAllProcInfo- 必要時先 stop stale proc
- 再顯式
StartProc起一個 fresh procnode- 最後使用 fresh
fsiSupervisorPath做 direct ask / direct execution 驗證GetVesion對fsi-supervisortimeout,不等於fsi-supervisor整體不可用;應至少再交叉驗證ListSessions或直接ExecCode。
--mode 與自訂 supervisee
--mode 只對 Akka.Proc.Supervisor.dll 自己 有意義:
--mode supervisor- 啟動 Supervisor process
--mode procnode- 啟動 ProcNode process,並在該 process 內 bootstrap
Akka.FSI.Supervisor
- 啟動 ProcNode process,並在該 process 內 bootstrap
若你透過 POST /api/proc/nodes/start 啟動的是別的程式,--mode 通常不該出現在該程式的 args 裡。
啟動另一個 .NET dll
如果 supervisee 是另一個 framework-dependent .NET dll,建議用:
{
"procId": "my-dotnet-app",
"fileName": "dotnet",
"args": [
"exec",
"--runtimeconfig", "/path/MyApp.runtimeconfig.json",
"--depsfile", "/path/MyApp.deps.json",
"/path/MyApp.dll",
"--arg1", "value1"
]
}
除非你啟動的仍然是 Akka.Proc.Supervisor.dll 本身,否則不要再加 --mode。
啟動 Python
如果 supervisee 是 Python:
{
"procId": "my-python-app",
"fileName": "python3",
"args": ["/path/app.py", "--arg1", "value1"]
}
同樣不需要 --mode。
什麼情況下才要 --mode procnode
只有當你要啟動的 child process 本身就是 Akka.Proc.Supervisor.dll,而且要把它當成可回報 fsiSupervisorPath 的 FSI host 時,才需要 --mode procnode。
probeMessage / probeIntervalMs 的用途與限制
probeMessage- 要定期送給 child proc 的 probe 內容
probeIntervalMs- 固定週期 probe 的毫秒數
probeCron- 若使用 Quartz cron,則用這個欄位排程 probe
這套 probe 機制不是 generic health check,也不是 generic IPC。實際流程是:
ProcSupervisor定時觸發 probe- 讀出
probeMessage - 用
ProcMessageParser解析該字串 - 轉送到 child proc 內的
fsi-supervisor - 依回應是否成功來判定 probe success / failure
所以:
- supervisee 若是
procnode + Akka.FSI.SupervisorprobeMessage有意義
- supervisee 若是一般
.NET dll、Python、或其他外部程式- 不應使用 FSI probe
/send也不成立
推薦 probe 設定:FSI host / procnode
建議使用不改動 session state、且能穩定反映 FSI 可用性的指令:
{
"probeMessage": "listsessions --all true",
"probeIntervalMs": 15000
}
這是目前最建議的預設 probe。
一般自訂 .NET dll supervisee
若 child process 不是 procnode,建議不要設 probeMessage:
{
"probeMessage": null,
"probeCron": null,
"probeIntervalMs": null
}
Python supervisee
同樣不建議設 probeMessage:
{
"probeMessage": null,
"probeCron": null,
"probeIntervalMs": null
}
若要監控這類 process,應另外定義 generic health contract,而不是重用 FSI probe。
StartProc ask timeout 與 GetProcInfo 補收斂
在上層 orchestration(例如 fsharp-devkit create_fsi_host)中,StartProc 有時會出現:
- child proc 其實已成功啟動
ProcRegistry也已看得到 snapshot- 但
StartProc這個 ask-reply 還沒在 timeout 前回來
因此:
StartProcask timeout- 不一定等於 host 建立失敗
較穩定的做法是:
- 先送
StartProc - 若
StartProcask timeout - 立刻在短時間內輪詢
GetProcInfo(procId) - 若很快查到 snapshot,將其視為「已成功建立,但命令回覆較慢」
- 只有在短時間輪詢後仍查不到 snapshot,才真正當作建立失敗
這就是「StartProc ask timeout 時,改用 GetProcInfo 短時間輪詢補收斂」的意思。
E2E 範例 (FSX 腳本)
以下是一個已驗證可跑的 smoke 範例,示範如何透過 REST API 啟動一個 ProcNode、查詢節點、送出 F# 程式碼,最後再停止該 Node。
執行前請確認已啟動 Supervisor。若是 repo 內 Debug build,可用:
dotnet exec \ --runtimeconfig Libs/Akka.Proc.Supervisor/bin/Debug/net10.0/Akka.Proc.Supervisor.runtimeconfig.json \ --depsfile Libs/Akka.Proc.Supervisor/bin/Debug/net10.0/Akka.Proc.Supervisor.deps.json \ Libs/Akka.Proc.Supervisor/bin/Debug/net10.0/Akka.Proc.Supervisor.dll \ --mode supervisor \ --systemname proc-system \ --host 127.0.0.1 \ --port 5001 \ --webhost 127.0.0.1 \ --webport 6001 \ --spawnnone
#r "nuget: FSharp.Data"
open System
open System.Threading
open FSharp.Data
// 設定 Supervisor 的 API 網址
let baseUrl = "http://localhost:6001/api/proc/nodes"
printfn "=== 1. 啟動預設的 ProcNode ==="
let startResp = Http.RequestString(
baseUrl + "/start-default",
httpMethod = "POST",
headers = [ HttpRequestHeaders.ContentType "application/json" ],
body = TextRequest """{"procId": "demo-node-01"}"""
)
printfn "啟動回應: %s" startResp
// 等待一下讓 Node 啟動並連上 Cluster
printfn "等待 Node 準備就緒..."
Thread.Sleep(3000)
printfn "=== 2. 查詢 Node 列表 ==="
let nodesResp = Http.RequestString(baseUrl, httpMethod = "GET")
printfn "Nodes: %s" nodesResp
printfn "=== 3. 查詢該 Node 的 sessions ==="
let sessionsResp =
Http.RequestString(
sprintf "%s/demo-node-01/sessions" baseUrl,
httpMethod = "GET"
)
printfn "Sessions: %s" sessionsResp
printfn "=== 4. 傳送 F# 程式碼到該 Node 執行 ==="
let fsiCommand = """exec --session mysession --code "let add a b = a + b\nadd 5 7" """
let sendPayload = sprintf """{"message": "%s"}""" fsiCommand
let sendResp =
Http.RequestString(
sprintf "%s/demo-node-01/send" baseUrl,
httpMethod = "POST",
headers = [ HttpRequestHeaders.ContentType "application/json" ],
body = TextRequest sendPayload
)
printfn "執行結果: %s" sendResp
printfn "=== 5. 關閉該 Node ==="
let stopResp = Http.RequestString(
sprintf "%s/demo-node-01/stop" baseUrl,
httpMethod = "POST",
headers = [ HttpRequestHeaders.ContentType "application/json" ],
body = TextRequest """{"force": true}"""
)
printfn "停止回應: %s" stopResp
printfn "=== 完成 ==="
send 指令的轉義規則
/send 目前是以 CLI-like 字串協定配合 ProcMessageParser 解析,因此若你要在 --code 內放多行 F#,請用轉義字元:
\\n代表換行\\r代表 CR\\t代表 tab\\\"代表雙引號\\\\代表反斜線
例如:
exec --session mysession --code "let add a b = a + b\nadd 5 7"
會在送進 FSI 前被還原成真正的兩行 F# 程式碼。
失敗案例現在的預期行為
若 F# 程式本身有語法錯誤或編譯錯誤,/send 現在的預期回應是:
- HTTP 仍正常回應
ExecResult.ok = falsediagnostics內有 FCS 診斷error.detail.errorType = "FSharp.Compiler.Interactive.Shell+FsiCompilationException"
也就是說,失敗會被表達成正常的 FSI 執行結果,而不是 transport/REST 反序列化錯誤。
關於設定檔 (.hocon)
系統會嘗試讀取目錄下的 .hocon 檔案,若不存在則使用內建預設值。您可以透過 akka.proc 區塊來調整 probe 週期、sharding 設定等:
akka.proc {
system-name = "proc-system"
probe-interval-ms = 15000
probe-failure-threshold = 3
restart-delay-ms = 3000
web {
host = "0.0.0.0"
port = 6001
}
}
部署診斷建議
若 deployed 環境看起來像:
proc-supervisor可回GetVesionGetAllProcInfo也有資料fsiSupervisorPath存在- 但
fsi-supervisor GetVesiontimeout
不要直接推論成 fsi-supervisor 壞掉。先做下面這組最小驗證:
- 用 direct actor ask 驗
proc-supervisor GetVesion - 停掉 stale proc
- 用
StartProc起一個 fresh procnode - 直接對 fresh
fsiSupervisorPath:ListSessionsExecCode
在 fsharp-devkit 的實際 deployment 驗證中,remote host isolation 與 session isolation 最終都是透過這種 direct actor-level 驗證確認成立;先前使用 bootstrap/stale proc target 的 timeout 不能直接當成底層 runtime 壞掉的證據。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Akka (>= 1.5.64)
- Akka.Cluster (>= 1.5.64)
- Akka.Cluster.Sharding (>= 1.5.64)
- Akka.DistributedData (>= 1.5.64)
- Akka.Remote (>= 1.5.64)
- FAkka.Argu (>= 10.1.201)
- FAkka.Fsi.Contracts (>= 10.1.201.4)
- FAkka.FSI.Supervisor (>= 1.564.101.201)
- FAkka.Quartz.Actor (>= 1.564.100.201)
- FAkka.Shared (>= 10.1.201)
- FAkka.WebSocket (>= 1.564.101.201)
- FSharp.Compiler.Service (>= 43.12.201)
- FSharp.Core (>= 10.1.201)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- MimeKit (>= 4.15.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on FAkka.Proc.Supervisor:
| Package | Downloads |
|---|---|
|
PulseTrade.Shared.fs
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.564.101.201 | 0 | 4/7/2026 |
| 1.562.101.201-dgx.25 | 43 | 3/30/2026 |
| 1.562.101.201-dgx.24 | 34 | 3/30/2026 |
| 1.562.101.201-dgx.23 | 41 | 3/30/2026 |
| 1.562.101.201-dgx.22 | 45 | 3/30/2026 |
| 1.562.101.201-dgx.21 | 45 | 3/30/2026 |
| 1.562.101.201-dgx.20 | 40 | 3/30/2026 |
| 1.562.101.201-dgx.19 | 40 | 3/29/2026 |
| 1.562.101.201-dgx.18 | 139 | 3/28/2026 |
| 1.562.101.201-dgx.17 | 131 | 3/28/2026 |
| 1.562.101.201-dgx.16 | 131 | 3/28/2026 |
| 1.562.101.201-dgx.15 | 135 | 3/28/2026 |
| 1.562.101.201-dgx.14 | 133 | 3/28/2026 |
| 1.562.101.201-dgx.13 | 132 | 3/28/2026 |
| 1.562.101.201-dgx.12 | 46 | 3/27/2026 |
| 1.562.101.201-dgx.11 | 40 | 3/26/2026 |
| 1.562.101.201-dgx.10 | 40 | 3/26/2026 |
| 1.562.101.201-dgx.9 | 40 | 3/26/2026 |
| 1.562.101.201-dgx.8 | 40 | 3/25/2026 |
| 1.562.101.201-dgx.7 | 43 | 3/25/2026 |