关于 ln-654-resource-lifecycle-auditor
ln-654-resource-lifecycle-auditor 是用于检查代码库中资源获取、释放、作用域和连接池实践的技能。它还会检查流式端点及错误路径,并输出带严重性标记的问题和合规评分。
主要功能
- 01检查资源作用域和清理
- 02审查流式端点的资源使用
- 03发现错误路径中的清理缺口
- 04检查连接池配置
- 05报告问题及合规评分
适用场景
- 01发现长时间流期间仍持有的会话
- 02检查异常或提前返回时的资源清理
- 03审查数据库连接池设置
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ levnikolaevich/ claude-code-skills --skill ln-654-resource-lifecycle-auditor安装后在 Claude Code 中输入/ln-654-resource-lifecycle-auditor确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/audit_output_schema.mdaudit_scoring.mdaudit_summary_contract.mdaudit_worker_core_contract.mdmcp_integration_patterns.mdmcp_tool_preferences.mdtwo_layer_detection.mdreferences/templates/audit_worker_report_template.md详细介绍
路径: 文件路径(
references/、../ln-*)相对于此技能目录。
资源生命周期审计器(L3 Worker)
类型: L3 Worker
专门审计资源获取/释放模式、作用域不匹配和连接池规范。
目的与范围
- 审计资源生命周期(优先级:高)
- 检查会话/连接作用域不匹配、流式端点持有资源、清理模式和连接池配置
- 将结构化发现写入文件,包含严重性、位置、工作量和建议
- 计算资源生命周期类别的合规分数(X/10)
输入
必须读取: 加载 references/audit_worker_core_contract.md 和 references/mcp_tool_preferences.md。
工具策略:你可能会作为独立子 Agent 运行,此时宿主的 AGENTS.md 不在作用域内,因此读取、搜索和编辑文件时默认优先使用 hex-line MCP。仅当 MCP 行为不明确时,才加载 references/mcp_integration_patterns.md。
接收包含以下内容的 contextStore:tech_stack、best_practices、db_config(数据库类型、ORM 设置、连接池配置、会话工厂)、codebase_root、output_dir。
支持领域模式: 支持 domain_mode + current_domain。
当引用链或调用路径能实质性地改进生命周期发现时,优先使用 hex-graph。当 hex-line 可用时,读取本地代码/配置优先使用 hex-line。如果 MCP 不可用、不受支持或未建立索引,则使用内置的 Read/Grep/Glob/Bash 继续操作,并在报告中说明所采用的回退方式。
工作流
检测策略:采用两层检测(候选扫描,然后上下文验证);仅当验证方法不明确时,才加载 references/two_layer_detection.md。
-
从 contextStore 解析上下文
- 提取 tech_stack、best_practices、db_config、output_dir
- 确定 scan_path
-
检测 DI 框架
- FastAPI
Depends()、Django 中间件、Spring@Autowired/@PersistenceContext、Express 中间件、Go wire/fx
- FastAPI
-
发现资源基础设施
- 查找会话/连接工厂模式(
sessionmaker、create_engine、DataSource、连接池创建) - 查找 DI 注册(
Depends()、@Inject、providers、中间件挂载) - 查找流式端点(SSE、WebSocket、长轮询、流式响应)
- 映射:哪些端点通过 DI 接收哪些资源
- 查找会话/连接工厂模式(
-
扫描代码库中的违规情况(6 项检查)
- 跟踪端点生命周期内的资源注入 -> 使用 -> 释放
- 分析流式端点是否持有资源
- 检查错误路径中的清理情况
-
收集发现,包含严重性、位置、工作量和建议
-
使用惩罚算法计算分数
-
编写报告: 根据
references/templates/audit_worker_report_template.md在内存中构建完整的 Markdown 报告,通过单次 Write 调用将其写入{output_dir}/ln-654--global.md -
返回摘要: 向协调器返回最简摘要(参见输出格式)
审计规则(优先级:高)
1. 资源作用域不匹配
**内容:**通过 DI 注入的资源在整个请求/连接作用域内都处于活动状态,但实际只在其中一小段时间内使用。
检测(Python/FastAPI):
- 步骤 1 - 查找依赖数据库会话的端点:
- 搜索:
async def\s+\w+\(.*Depends\(get_db\)|Depends\(get_session\)|db:\s*AsyncSession|session:\s*AsyncSession
- 搜索:
- 步骤 2 - 衡量端点函数体内会话的使用范围:
- 统计首次和最后一次使用
session\.|db\.|await.*repo之间的行数 - 统计端点函数体的总行数
- 统计首次和最后一次使用
- 步骤 3 - 若
usage_lines / total_lines < 0.2,则标记(会话使用范围小于函数体的 20%)- 尤其要注意:会话仅在函数开头使用(用于身份验证检查、初始加载),但函数后续仍执行非数据库操作
检测(Node.js/Express):
- 中间件在请求开始时注入
req.db或req.knex - 搜索:
app\.use.*pool|app\.use.*knex|app\.use.*prisma(中间件注入) - 路由处理程序仅在函数体前 20% 的范围内使用
req.db
检测(Java/Spring):
- 在包含大量非数据库处理的方法上使用
@Transactional - 注入了
EntityManager,但仅短暂使用 - 搜索:
@Autowired.*EntityManager|@PersistenceContext,并分析方法体
检测(Go):
- 将
sql.DB或*gorm.DB传递给处理程序,仅使用一次,之后进行长时间处理 - 搜索:
func.*Handler.*\*sql\.DB|func.*Handler.*\*gorm\.DB
严重性:
- **严重:**流式端点(SSE、WebSocket)的会话作用域不匹配——会话被占用数分钟或数小时
- **高:**包含外部 API 调用的端点存在会话作用域不匹配(网络延迟期间会话一直被占用)
- **中:**包含超过 50 行非数据库处理的端点存在会话作用域不匹配
**建议:**将数据库操作提取到作用域明确的函数中;仅在需要的时段获取会话;使用 async with get_session() as session: 代码块,而不是在端点级别通过 DI 注入。
**工作量:**M(将 DI 重构为作用域内获取)
2. 流式端点占用资源
**内容:**SSE、WebSocket 或长轮询端点在整个流传输期间一直占用数据库会话/连接。
检测(Python/FastAPI):
- 步骤 1 - 查找流式端点:
- 搜索:
StreamingResponse|EventSourceResponse|SSE|async def.*websocket|@app\.websocket - 搜索:
yield\s+.*event|yield\s+.*data:|async for.*yield(SSE 生成器模式)
- 搜索:
- 步骤 2 - 检查流式函数/生成器的作用域内是否有数据库会话:
- 端点签名中的
Depends()会话 -> 整个流传输期间都会被占用 - 生成器内部通过上下文管理器获取的会话 -> 作用域明确(正常)
- 端点签名中的
- 步骤 3 - 分析生成器内的会话使用情况:
- 如果会话只在开头使用一次(用于身份验证/权限检查),之后流循环不再访问数据库,则说明作用域不匹配
检测(Node.js):
- 搜索:
res\.write\(|res\.flush\(|Server-Sent Events|new WebSocket|ws\.on\( - 检查是否在流循环开始前获取了连接/连接池客户端,且未释放
检测(Java/Spring):
- 搜索:
SseEmitter|WebSocketHandler|StreamingResponseBody - 检查
@Transactional是否包裹了流式方法
检测(Go):
- 搜索:
Flusher|http\.Flusher|websocket\.Conn - 检查是否在刷新循环期间一直占用
*sql.DB或事务
严重性:
- **严重:**整个 SSE/WebSocket 流传输期间都占用数据库会话/连接(高负载下会耗尽连接池)
- **高:**长轮询期间一直占用数据库连接(超时超过 30 秒)
**建议:**在流传输开始前执行身份验证/权限检查:获取会话、检查身份验证、释放会话,然后再开始流传输。对于流传输期间的数据库访问,使用单独的作用域会话。
**工作量:**M(重构端点,在流传输前释放会话)
3. 缺少资源清理模式
是什么: 获取资源后未确保清理(没有 try/finally、上下文管理器或 close())。
检测(Python):
- Grep:
session\s*=\s*Session\(\)|session\s*=\s*sessionmaker|engine\.connect\(\)未置于with或async with中 - Grep:
connection\s*=\s*pool\.acquire\(\)|conn\s*=\s*await.*connect\(\)后面没有try:.*finally:.*close\(\) - 模式:
session = get_session()未使用上下文管理器 - 可排除的安全模式:
async with session_factory() as session:、with engine.connect() as conn:
检测(Node.js):
- Grep:
pool\.connect\(\)|knex\.client\.acquireConnection|\.getConnection\(\),且同一函数中没有对应的.release()或.end() - Grep:
createConnection\(\),且未在 try/finally 中调用.destroy()
检测(Java):
- Grep:
getConnection\(\)|dataSource\.getConnection\(\),未使用 try-with-resources - 模式:
Connection conn = ds.getConnection(),未使用try (Connection conn = ...)语法
检测(Go):
- Grep:
sql\.Open\(|db\.Begin\(\),且没有defer.*Close\(\)|defer.*Rollback\(\) - 模式:
tx, err := db.Begin(),但没有defer tx.Rollback()
严重程度:
- 高: 获取会话/连接后未确保清理(异常时会泄漏)
- 中: 非关键路径中未清理文件句柄或游标
例外: 在开始流式传输/长轮询前获取并释放会话 -> 跳过。将 NullPool / pool_size 配置为无服务器设计并有文档说明 -> 跳过。
建议: 确保资源在所有退出路径中都能得到清理(使用上下文管理器、try-finally 或框架管理的生命周期)。
工作量: S(包装在上下文管理器中或添加 defer)
4. 连接池配置缺口
内容: 缺少连接池健康监控、连接前预检和回收机制,也没有溢出限制。
检测(Python/SQLAlchemy):
- 搜索
create_engine\(|create_async_engine\:- 缺少
pool_pre_ping=True→ 无法检测失效连接 - 缺少
pool_recycle→ 连接存活时间超过数据库服务器超时时间(默认值:MySQL 为 8 小时,PG 不限) - 缺少
pool_size→ 使用默认值 5(对生产环境来说可能过小) - 缺少
max_overflow→ 高负载下溢出连接数不受限制 - Web 服务中使用
pool_size=0或NullPool→ 不使用连接池(反模式)
- 缺少
- 搜索连接池事件监听器:
- 缺少
@event.listens_for(engine, "invalidate")→ 无法查看连接失效情况 - 缺少
@event.listens_for(engine, "checkout")→ 无法监控连接取出情况 - 缺少
@event.listens_for(engine, "checkin")→ 无法监控连接归还情况
- 缺少
检测(Node.js):
- 搜索
createPool\(|new Pool\(:- 缺少
min/max配置 - 缺少
idleTimeoutMillis或reapIntervalMillis - 缺少连接验证(
validateConnection、testOnBorrow)
- 缺少
检测(Java/Spring):
- 搜索:
DataSource|HikariConfig|HikariDataSource:- 缺少
leakDetectionThreshold - 缺少
maximumPoolSize(默认值为 10) - 缺少
connectionTestQuery或connectionInitSql
- 缺少
检测(Go):
- 搜索:
sql\.Open\(:- 缺少
db.SetMaxOpenConns() - 缺少
db.SetMaxIdleConns() - 缺少
db.SetConnMaxLifetime()
- 缺少
严重程度:
- 高: 既没有 pool_pre_ping,也没有 pool_recycle(失效连接会被悄然使用)
- 高: Web 服务没有 max_overflow 限制(高负载下连接数会无限增长)
- 中: 缺少连接池事件监听器(无法查看连接池健康状况)
- 中: 缺少泄漏检测阈值(Java/HikariCP)
- 低: 连接池大小为默认值(对小型服务可能足够)
视情况而定的例外:
- NullPool 可用于无服务器/Lambda
- 对于低流量服务,pool_size=5 可能足够
建议: 配置 pool_pre_ping=True、将 pool_recycle 设为小于数据库服务器超时时间的值,并根据预期并发量设置合适的 pool_size;添加连接池事件监听器以进行监控。
工作量: S(添加配置参数),M(添加事件监听器/监控)
5. 错误路径中未关闭的资源
内容: 异常/错误处理路径跳过资源清理。
检测(Python):
- 查找包含
raise或return、但之前没有session.close()、conn.close()或cursor.close()的except代码块 - 模式:
except Exception: logger.error(...); raise(重新抛出异常但不清理) - 查找使用数据库会话、但未处理 GeneratorExit 的生成器函数:
- 搜索:
async def.*yield.*session|def.*yield.*session,且没有try:.*finally:.*close\(\)
- 搜索:
检测(Node.js):
- 搜索会执行
throw或return、但没有释放连接的catch\s*\(代码块 - 模式:
pool.connect().then(client => { ... }),但没有.finally(() => client.release()) - 用于清理的 Promise 链中缺少
.finally()
检测(Java):
- 搜索
catch\s*\(代码块:如果在try中打开了连接,却没有finally { conn.close() } - 对 AutoCloseable 资源未使用 try-with-resources
检测(Go):
- 搜索:在资源清理的
defer语句之前出现if err != nil \{.*return - 模式:在
Open()和defer Close()之间检查错误,并在未关闭资源的情况下返回
严重程度:
- 严重: 高频端点的错误路径中存在会话/连接泄漏(导致连接池耗尽)
- 高: API 处理程序的错误路径中存在资源泄漏
- 中: 后台任务的错误路径中存在资源泄漏
建议: 在任何可能失败的代码执行之前,使用上下文管理器/try-with-resources/defer;对于生成器,在 yield 外层添加 try/finally。
工作量: S(调整结构,使资源获取发生在可能出错的路径之前)
6. 资源工厂与注入反模式
内容: 使用框架 DI 将短生命周期资源注入长生命周期上下文,而不是使用工厂模式。
检测(Python/FastAPI):
- 步骤 1 - 查找通过 DI 注入的端点签名中的会话:
- Grep:
Depends\(get_db\)|Depends\(get_session\)|Depends\(get_async_session\)
- Grep:
- 步骤 2 - 判定端点生命周期:
- 短生命周期:常规 REST 端点(请求/响应)→ 可以使用 DI 注入
- 长生命周期:SSE(
StreamingResponse、EventSourceResponse)、WebSocket(@app.websocket)、后台任务(BackgroundTasks.add_task)
- 步骤 3 - 标记长生命周期端点中的 DI 注入:
- 长生命周期端点应在需要时使用工厂模式:
async with session_factory() as session: - 不应在端点级别使用
session: AsyncSession = Depends(get_session)
- 长生命周期端点应在需要时使用工厂模式:
检测(Node.js/Express):
- 中间件注入的池连接(
req.db)被用于 WebSocket 处理程序或 SSE 路由 - 应在需要时使用:
const conn = await pool.connect(); try { ... } finally { conn.release() }
检测(Java/Spring):
- SSE 端点(
SseEmitter)所在的@Controller中存在@Autowired EntityManager - 应使用:通过 EntityManagerFactory 以编程方式创建 EntityManager
检测(Go):
- 在构造处理程序时注入了
*sql.DB,但应按操作获取*sql.Conn
严重级别:
- CRITICAL: SSE/WebSocket 端点中通过 DI 注入的会话(会话的存续时间比预期作用域长出多个数量级)
- HIGH: 通过 DI 注入的会话被传递给后台任务(任务的存续时间超过请求)
建议: 对于长生命周期上下文,使用工厂模式;注入工厂(sessionmaker、池),而不是会话/连接本身。
工作量: M(将 DI 注入从会话改为会话工厂,并添加作用域内的获取逻辑)
评分算法
必须阅读: 加载 references/audit_scoring.md。
输出格式
必须阅读: 加载 references/templates/audit_worker_report_template.md。
按照 references/audit_summary_contract.md 编写 JSON 摘要。在托管模式下,调用方会同时传入 runId 和 summaryArtifactPath;在独立模式下,工作器会按照共享契约生成自己的运行作用域产物路径。
将报告写入 {output_dir}/ln-654--global.md,其中 category: "Resource Lifecycle",检查项为:resource_scope_mismatch、streaming_resource_holding、missing_cleanup、pool_configuration、error_path_leak、factory_vs_injection。
按照 references/audit_summary_contract.md 返回摘要。
当 summaryArtifactPath 缺失时,将独立运行时摘要写入 .hex-skills/runtime-artifacts/runs/{run_id}/evaluation-worker/{worker}--{identifier}.json,并可选择在结构化输出中回显相同摘要。
Report written: .hex-skills/runtime-artifacts/runs/{run_id}/audit-report/ln-654--global.md
Score: X.X/10 | Issues: N (C:N H:N M:N L:N)
关键规则
遵循已加载的 references/audit_worker_core_contract.md。
- 不要自动修复: 仅报告问题
- 考虑 DI: 了解框架依赖注入的生命周期作用域(请求、单例、瞬态)
- 先识别框架: 检查注入模式前,先识别 DI 框架
- 先检测流式处理: 作用域分析前,先查找所有流式/长生命周期端点
- 排除测试: 不要标记测试夹具、测试会话设置或模拟会话
- 排除 CLI/脚本: 对单次运行的脚本,DI 作用域不匹配无关紧要
- 合理评估工作量: S = <1h,M = 1-4h,L = >4h
- 池配置取决于上下文: NullPool 对无服务器/Lambda 场景有效;对于低流量服务,pool_size=5 可能也没问题
- 注意安全模式: 不要标记
async with、with、try-with-resources、defer内部的资源(已进行管理)
完成定义
应用已加载的 references/audit_worker_core_contract.md。
- contextStore 已成功解析(包括 output_dir、db_config)
- 已确定 scan_path
- 已检测到 DI 框架(FastAPI Depends、Django middleware、Spring @Autowired、Express middleware、Go wire)
- 已盘点流式端点
- 已完成全部 6 项检查:
- 资源作用域不匹配、流式资源占用、缺少清理、连接池配置、错误路径泄漏、工厂与注入
- 已收集发现项,并注明严重程度、位置、工作量和建议
- 已使用惩罚算法计算分数
- 已将报告写入
{output_dir}/ln-654--global.md(使用单次 Write 调用原子写入) - 已按契约编写摘要
参考文件
- 审计输出架构:
references/audit_output_schema.md
版本: 1.0.0 最后更新: 2026-03-03