用途
本技能用于指导在 Effect(TypeScript)中进行结构化资源管理。Effect 提供结构化资源管理能力,保证即使在发生错误或效果被中断时也能执行清理。这适用于数据库连接、文件句柄、网络套接字、锁和信号量,以及任何需要清理的资源。当用户询问 Effect 资源、acquireRelease、Scope、finalizers、资源清理、Effect.addFinalizer 等话题时使用。
核心概念:Scope
Scope 是一个跟踪资源并确保其清理的上下文:
Effect<A, E, R | Scope>
// ^^^^^ 表示资源需要清理
主要能力
Effect.acquireRelease
安全资源管理的基本模式:
import { Effect } from "effect"
const managedFile = Effect.acquireRelease(
Effect.sync(() => fs.openSync("file.txt", "r")),
(fd) => Effect.sync(() => fs.closeSync(fd))
)
使用资源:
const program = Effect.gen(function* () {
const fd = yield* managedFile
const content = yield* Effect.sync(() => fs.readFileSync(fd, "utf-8"))
return content
})
// 运行并自动管理 scope
const result = yield* Effect.scoped(program)
Effect.scoped
通过管理 scope 将带 scope 的 effect 转换为常规 effect:
const runnable = Effect.scoped(program)
当 scoped 块完成时 scope 关闭,触发所有 finalizer。
acquireUseRelease 模式
对于更简单的场景,将 acquire/use/release 合并为一次调用:
const readFile = (path: string) =>
Effect.acquireUseRelease(
Effect.sync(() => fs.openSync(path, "r")),
(fd) => Effect.sync(() => fs.readFileSync(fd, "utf-8")),
(fd) => Effect.sync(() => fs.closeSync(fd))
)
Finalizers
Effect.addFinalizer —— 向当前 scope 添加清理逻辑:
const program = Effect.gen(function* () {
yield* Effect.addFinalizer(() =>
Effect.log("Cleanup running!")
)
// ... 执行工作 ...
return result
})
Effect.ensuring —— 在 effect 完成后(成功或失败)运行清理:
const withCleanup = someEffect.pipe(
Effect.ensuring(
Effect.log("Always runs after effect")
)
)
Effect.onExit —— 根据退出状态运行不同的清理:
const withExitHandler = someEffect.pipe(
Effect.onExit((exit) =>
Exit.isSuccess(exit)
? Effect.log("Succeeded!")
: Effect.log("Failed or interrupted")
)
)
多个资源
顺序获取:
const program = Effect.gen(function* () {
const db = yield* acquireDbConnection
const cache = yield* acquireRedisConnection
})
const result = yield* Effect.scoped(program)
并行获取:
const program = Effect.gen(function* () {
const [db, cache] = yield* Effect.all([
acquireDbConnection,
acquireRedisConnection
])
})
资源模式
数据库连接池:
const DbPool = Effect.acquireRelease(
Effect.promise(() => createPool({
host: "localhost",
database: "mydb",
max: 10
})),
(pool) => Effect.promise(() => pool.end())
)
const query = (sql: string) =>
Effect.gen(function* () {
const pool = yield* DbPool
return yield* Effect.tryPromise(() => pool.query(sql))
})
文件句柄:
const withFile = <A>(
path: string,
use: (handle: FileHandle) => Effect.Effect<A>
) =>
Effect.acquireUseRelease(
Effect.promise(() => fs.promises.open(path)),
use,
(handle) => Effect.promise(() => handle.close())
)
锁/Mutex:
const withLock = <A>(
lock: Lock,
effect: Effect.Effect<A>
) =>
Effect.acquireUseRelease(
lock.acquire,
() => effect,
() => lock.release
)
分层资源
使用 Layer.scoped 管理服务级资源:
const DatabaseLive = Layer.scoped(
Database,
Effect.gen(function* () {
const pool = yield* Effect.acquireRelease(
createPool(),
(pool) => Effect.promise(() => pool.end())
)
return {
query: (sql) => Effect.tryPromise(() => pool.query(sql))
}
})
)
清理中的错误处理
Finalizer 不应失败,但如果失败:
const safeRelease = (resource: Resource) =>
Effect.sync(() => resource.close()).pipe(
Effect.catchAll((error) =>
Effect.logError("Cleanup failed", error)
)
)
const managed = Effect.acquireRelease(
acquire,
safeRelease
)
中断安全
即使被中断,资源也会被清理:
const program = Effect.gen(function* () {
const resource = yield* acquireResource
yield* Effect.sleep("1 hour")
})
const result = yield* program.pipe(
Effect.scoped,
Effect.timeout("1 second")
)
最佳实践
- 对成对操作使用 acquireRelease——保证清理。
- 保持 finalizer 简单且不可失败——记录错误而不是抛出。
- 在合适的边界使用 Effect.scoped——既不过宽也不过窄。
- 按获取的反序进行清理——Effect 会自动处理。
- 对服务级资源使用 Layer.scoped——生命周期与 layer 绑定。
额外资源
关于全面的资源管理文档,请查阅 ${CLAUDE_PLUGIN_ROOT}/references/llms-full.txt。
搜索以下章节:
- "Introduction"(Resource Management)了解核心概念
- "Scope"了解详细的 scope 机制
- "Managing Layers"了解 Layer.scoped 模式
限制
除上述内容外,本技能的收费、价格、平台支持、实际效果等具体信息暂未提供。