生命周期与 effect:让 Cordis 注册可以回卷
跟随 Fiber 从 PENDING 到 DISPOSED,理解 effect、disposer 与 HMR 如何共同管理插件副作用。
核心结论:插件加载时创建资源,卸载时执行 disposer;Fiber 把两件事绑定在同一个生命周期里。
所以 HMR 不是“再 import 一次文件”这么简单。实现可以先导入替换模块,再卸载旧 Fiber;关键不变量是旧 Fiber 的监听器、服务、子插件和外部资源必须在新 Fiber 激活前撤销干净。
01 / Fiber 是插件实例的运行时句柄
一个插件实例会经历:
PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED
↘ FAILEDPENDING:插件已声明,但依赖尚未满足。LOADING/ACTIVE:apply正在运行或已经完成。FAILED:配置校验或apply抛出异常。UNLOADING/DISPOSED:清理正在执行或已经完成。
Fiber 不是一个抽象状态标签。它是插件实例拥有的生命周期句柄,fiber.dispose() 会等待清理完成,并递归卸载它挂载的子插件。
02 / 用 effect 包住外部资源
Cordis 已经知道如何撤销自己的注册;定时器、连接和 watcher 等外部资源则需要显式包装:
ctx.effect(() => {
const timer = setInterval(() => console.log('tick'), 200)
return () => {
clearInterval(timer)
console.log('cleaned up')
}
})主体在加载时执行,返回的函数在卸载时执行。插件作者不需要在某个全局 shutdown 函数里猜测资源属于谁。
03 / 常见注册本身也是 effect
下列操作会把清理关系附着到当前 Fiber:
ctx.on()注册事件监听器。ctx.plugin()挂载子插件。Service注册服务名称。ctx.effect()包装 Cordis 尚未管理的外部资源。
卸载时,Fiber 按注册的逆序收集 disposer,再并发启动顶层清理;多个并列 effect 的异步清理可以并发运行,而 fiber.dispose() 会等待它们完成。如果两个资源之间有严格顺序要求,把清理放在同一个 effect 中,并在其中显式 await。
04 / 一个可验证的最小例子
import type { Context } from '@deepseek-ai/cordis'
function heartbeat(ctx: Context) {
console.log('heartbeat plugin loading')
ctx.effect(() => {
const timer = setInterval(() => console.log('tick'), 200)
return () => {
clearInterval(timer)
console.log('heartbeat cleaned up')
}
})
}
export function apply(ctx: Context) {
const fiber = ctx.plugin(heartbeat)
ctx.effect(() => {
const shutdown = setTimeout(async () => {
await fiber.dispose()
console.log('disposed')
process.exit(0)
}, 700)
return () => clearTimeout(shutdown)
})
}输出会先出现 heartbeat 和 tick,随后出现 cleanup 和 disposed。重要的不是日志,而是 fiber.dispose() 返回前清理已经完成。
05 / effect 是 HMR 的基础设施
HMR 可以把代码刷新变成可控的运行时转换:先导入替换模块,再卸载旧 Fiber 并回卷 effect,随后注册并激活替换 Fiber。没有 disposer 的资源不会神奇消失,因此每个插件都应该让自己创建的资源有明确 owner。
在 DeepSeek Harness 中,工具注册、事件监听、模型适配器和 agent loop 都通过插件进入这套生命周期。卸载不是文档里的约定,而是运行时动作。
下一步
更多文章
inject:让依赖决定加载顺序,而不是 YAML 行号
理解 Cordis 的 PENDING、依赖跟踪和可选服务探测,解释为什么 provider 更换会自动带动 consumer。
Cordis:把运行中的应用变成一棵可逆的插件树
从 cordis.yml、Loader 和 Context 开始,理解 Cordis 如何让 DeepSeek Harness 组合、替换并安全卸载运行时能力。
组合与热重载(HMR):导入新模块,回卷旧 Fiber,再激活替换
理解稳定 id、配置组和 Cordis HMR 的卸载—重载流程,并学会定位始终停在 PENDING 的插件。
邮件列表
加入我们的社区
订阅邮件列表,及时获取最新消息和更新