如果你在 AWS CodeBuild 里跑 Serverless Framework 部署,且 serverless.ts 通过相对路径引入了其他 .ts 文件,大概率遇到过命令直接卡死、日志不再滚动的情况。4.36.1 把这个让人头疼的死锁问题修掉了。
死锁是怎么发生的
Serverless Framework 支持 TypeScript 配置文件(serverless.ts),框架在启动时会动态编译并加载这些文件。问题出在"多文件"场景——当 serverless.ts 通过相对导入引用同目录下的其他 .ts 文件时:
// serverless.ts
import { baseConfig } from './base';
import { awsResources } from './resources/aws';
框架的 TypeScript 编译流程在处理嵌套的相对导入时,内部锁的获取顺序出现了交叉:主线程持有编译锁等待子模块加载完成,而子模块加载又需要同一把锁来注册依赖。两个方向互相等待,死锁就形成了。
这个 bug 在本地开发时不容易触发,因为本地机器的 I/O 和 CPU 调度快,竞争窗口极窄。但 AWS CodeBuild 的容器环境资源受限、调度更慢,竞争窗口被拉大,死锁几乎必现——这也是社区里大部分报告来自 CodeBuild 的原因。
4.36.1 的修复思路
修复的核心是重构了 TypeScript 配置加载的锁机制:将编译阶段和依赖注册阶段拆成两个独立的锁,消除了交叉获取的可能。嵌套的相对导入现在走一条无锁的依赖收集路径,只在最终合并结果时加锁。
简单说:原来一把锁管两件事,现在两把锁各管各的,不再有互相等待。
实际验证:多文件 TypeScript 配置项目
下面是一个可以直接跑的示例项目,用来确认死锁已修复。如果你还在用旧版本,可以先复现问题再升级对比。
项目结构
serverless-ts-demo/
├── serverless.ts
├── config/
│ ├── base.ts
│ └── resources.ts
├── handler.ts
└── package.json
config/base.ts
export const baseConfig = {
service: 'ts-deadlock-test',
provider: {
name: 'aws',
runtime: 'nodejs18.x',
region: 'ap-northeast-1',
},
};
config/resources.ts
export const resources = {
Resources: {
MyBucket: {
Type: 'AWS::S3::Bucket',
Properties: {
BucketName: 'ts-deadlock-test-bucket',
},
},
},
};
serverless.ts — 多文件导入的入口
import { baseConfig } from './config/base';
import { resources } from './config/resources';
export default {
...baseConfig,
functions: {
hello: {
handler: 'handler.hello',
events: [{ http: { method: 'get', path: 'hello' } }],
},
},
resources: resources,
};
handler.ts
export const hello = async () => {
return {
statusCode: 200,
body: JSON.stringify({ message: 'deadlock test ok' }),
};
};
package.json
{
"name": "serverless-ts-demo",
"version": "1.0.0",
"devDependencies": {
"serverless": "^4.36.1",
"typescript": "^5.3.0"
}
}
安装与验证
# 初始化项目
mkdir serverless-ts-demo && cd serverless-ts-demo
# 按上面的结构创建文件后:
npm install
# 验证配置能正常加载(不再卡死)
npx serverless print
# 如果输出完整的合并配置 JSON,说明死锁已修复
# 在 CodeBuild 中同样可以加入这一步作为部署前检查
如果你用的是 4.36.1 之前的版本,serverless print 大概率会卡住不动,需要 Ctrl+C 强制退出。升级后应立即返回结果。
升级建议与注意事项
- 直接升级到 4.36.1:这是纯 bugfix 版本,没有破坏性变更,
npm i serverless@4.36.1即可。 - CodeBuild 流程加验证步骤:在部署命令前插入
serverless print,如果卡住立刻失败,避免后续步骤无限等待浪费构建时间。 - 单文件配置不受影响:如果你的
serverless.ts没有相对导入其他.ts文件,这个 bug 和你无关,但升级仍然没有风险。 - 留意嵌套深度:修复覆盖了多层嵌套的相对导入,但如果你有特别深的导入链(超过 5 层),建议在升级后做一次完整的
serverless package测试,确认编译耗时没有异常增长。
这个死锁问题存在了一段时间,在 CI 环境里尤其折磨人——部署命令卡死、没有报错、没有日志,只能靠超时来发现。4.36.1 把这个暗坑填上了,值得尽快更新。