Serverless Framework 4.36.1:多文件 TypeScript 配置的死锁陷阱终于修了

2026-05-15 29 预计阅读时间:1 分钟
来源:oschina.net AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:6 分钟

如果你在 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 把这个暗坑填上了,值得尽快更新。


相关推荐