docs(sdk): 补全自动重启的真实约束(退避 / 上限 / 非无感)

原文只说「插件崩溃时平台自动拉起,保障服务可用性」,读起来像
无感瞬时恢复。实测与源码都不是这样:

## 补齐的默认参数(内核 internal/plugin/registry.go)

| 参数 | 值 | 含义 |
|---|---|---|
| procRestartBackoff | 1s | 第 n 次重启前等 n × 1s(线性退避) |
| procMaxRestarts | 3 | 窗口内重启次数上限 |
| procCrashWindow | 5min | 窗口内无新崩溃则计数归零 |

即实际序列 1s → 2s → 3s;同一 5 分钟窗口内第 4 次崩溃(n > 3)不再
自动拉起,交人工介入。首次重启就要等 1s,期间该插件的工具是缺席的、
调用会报错 —— 需要秒级就位的插件应在 OnStart 里自建重连与状态重建。

## 顺带改准一处混淆

`SetAutoRestart` 的文档写「崩溃后自动重载」—— 把「重启」说成了
「重载」。重载是换 plugin.bin 后重新加载那条路径(ReloadOne),
与崩溃自愈不是一回事。已在文档里写清,并附上退避与上限。

这个混淆与内核侧 HEAD 修正的 README/官网是同一处(源码注释里
「足够快到用户感知不到工具缺席」也是同一类无实测支撑的主观断言,
已在主仓同批改掉)。

中英双版同步更新。
This commit is contained in:
JianFeeeee
2026-09-21 10:34:27 +08:00
parent 7717bf5ca5
commit 5af2a86816
3 changed files with 30 additions and 1 deletions

View File

@ -487,6 +487,18 @@ enabled := sdk.AutoRestart()
插件崩溃时平台自动拉起,保障服务可用性。
重启是**有节制的**,默认参数(内核 `internal/plugin/registry.go`):
| 参数 | 值 | 含义 |
|---|---|---|
| `procRestartBackoff` | `1s` | 第 n 次重启前等 `n × 1s`(线性退避,非立即拉起) |
| `procMaxRestarts` | `3` | 窗口内允许的重启次数上限 |
| `procCrashWindow` | `5min` | 窗口内无新崩溃则计数归零 |
即崩溃后的实际序列是 **1s → 2s → 3s**;同一 5 分钟窗口内第 **4** 次崩溃
(`n > 3`)**不再自动拉起**,交人工介入。这不是「立即无感恢复」——
如果插件需要秒级就位,请自己在 `OnStart` 里做好重连与重建。
> ⚠️ `SetAutoRestart` 的典型用法是「外部连接建好后再判定能否自动重启」,而连接建立
> 通常在后台 goroutine 里,内核又在另一个 goroutine 读它——这对读写天然并发。
> **SDK 1.1.0 已给这个标志与全部 API 字段加锁**(`-race` 实测 11 处竞态,

View File

@ -443,6 +443,19 @@ enabled := sdk.AutoRestart()
The platform automatically restarts the plugin on crash, ensuring service availability.
Restarts are **rate-limited**. Defaults (kernel `internal/plugin/registry.go`):
| Parameter | Value | Meaning |
|---|---|---|
| `procRestartBackoff` | `1s` | Before restart #n, wait `n × 1s` (linear backoff, not immediate) |
| `procMaxRestarts` | `3` | Max restarts within the window |
| `procCrashWindow` | `5min` | No new crash within the window resets the count |
So the actual sequence is **1s → 2s → 3s**; the **4th** crash in the same 5-minute
window (`n > 3`) is **not** restarted automatically and needs manual intervention.
This is not instant, invisible recovery — if your plugin must be back in seconds,
reconnect and rebuild your own state in `OnStart`.
> ⚠️ `SetAutoRestart` is typically used to decide whether auto-restart is safe *after* an
> external connection has been established, and that connection setup usually happens in a
> background goroutine while the kernel reads the flag from another one — which is inherently

View File

@ -775,8 +775,12 @@ func (s *PluginSDK) SetToolBlocks(blocks []ContentBlock) {
}
}
// SetAutoRestart 设置插件是否允许内核自动重启(崩溃后自动重载)。
// SetAutoRestart 设置插件崩溃后内核是否自动重启它。
// 默认 true。如果插件有无法恢复的状态(如外部连接),应设为 false。
//
// 重启是有限度的:线性退避(第 n 次等 n×1s,即 1s→2s→3s),
// 且同一 5 分钟窗口内第 4 次崩溃就停下不再拉起(详见 README)。
// 注意这与「重载」(换 plugin.bin 后重新加载)是两回事。
func (s *PluginSDK) SetAutoRestart(enabled bool) {
s.apiMu.Lock()
s.autoRestart = enabled