Serverless+TypeORM+AWS Lambda数据库初始化时机问题求助
问题描述
我正在开发一个基于TypeScript、Serverless、TypeORM和AWS Lambda的项目,数据库初始化代码写在data-source.ts中:
export const AppDataSource = new DataSource({ type: "postgres", host: "localhost", port: 5432, username: "use", password: "pass", database: "dbname", synchronize: false, logging: true, entities: [CarEntity], subscribers: [], migrations: [], }) // * (see below)This code is in the initDB() function that I call in the create function. AppDataSource.initialize() .then(async () => { console.log("DB Initialized") }) .catch((error) => console.log("Error: ", error))
目前遇到的问题是:数据库还未完成初始化,handler函数就已执行,导致报错信息为"errorMessage": "No metadata for \"CarEntity\" was found."。若在create handler中取消注释await initDB()代码,即可正常创建并保存Car实体到数据库。
项目的serverless.yml配置如下:
service: aws-node-typescript # NOTE: update this with your service name frameworkVersion: '3' provider: name: aws runtime: nodejs18.x functions: create: handler: src/handler.create events: - http: path: '' method: 'post' update: handler: src/handler.update events: - http: path: '' method: 'put' get: handler: src/handler.get events: - http: path: '' method: 'get' plugins: - serverless-esbuild
想请教:数据库的正确初始化位置应该在哪里?
解决方案
在AWS Lambda环境下,TypeORM的数据源初始化必须确保在handler执行前完成异步初始化,不能依赖顶层的AppDataSource.initialize()(因为Lambda冷启动时,顶层代码的异步操作不会等待完成就会执行handler)。
正确的实现步骤:
- 封装带单例判断的初始化函数
修改data-source.ts,把初始化逻辑改成可等待的异步函数,同时判断数据源是否已初始化,避免重复操作:
// data-source.ts import { DataSource } from "typeorm" import { CarEntity } from "./entities/CarEntity" export const AppDataSource = new DataSource({ type: "postgres", host: "localhost", port: 5432, username: "use", password: "pass", database: "dbname", synchronize: false, logging: true, entities: [CarEntity], subscribers: [], migrations: [], }) export async function initDB() { if (!AppDataSource.isInitialized) { await AppDataSource.initialize() console.log("DB Initialized") } }
- 在每个Lambda handler开头执行初始化
所有需要操作数据库的handler,都要在业务逻辑前await initDB():
// src/handler.ts import { initDB } from './data-source' import { AppDataSource } from './data-source' import { CarEntity } from './entities/CarEntity' export const create = async (event: any) => { // 先确保数据库初始化完成 await initDB() const carRepository = AppDataSource.getRepository(CarEntity) // 执行创建Car实体的业务逻辑... } export const update = async (event: any) => { await initDB() // 执行更新逻辑... } export const get = async (event: any) => { await initDB() // 执行查询逻辑... }
- 关键原因说明
Lambda的执行机制是:冷启动时加载代码并执行顶层逻辑,但顶层的异步操作(比如.then()链式调用)不会阻塞handler的执行,导致handler运行时数据源还未完成初始化,触发"No metadata"错误。而在handler内使用await可以强制等待初始化完成后再执行业务代码,同时isInitialized判断能在热启动时复用已初始化的数据源,提升请求处理效率。
内容的提问来源于stack exchange,提问作者Mauricio Etchevest
相关产品推荐
相关产品推荐

