refactor(server): 迁移改官方 migrationsRun 模式,移除自定义启动 runner
All checks were successful
CI / check (pull_request) Successful in 3m41s
Dependency Check / check (pull_request) Successful in 2m22s

TypeOrmModule 连接后自动执行未跑迁移(glob 自动发现,ts-node/dist 均匹配),
删除 main.ts 启动钩子与独立 DataSource。部署脚本显式 migration:run 保留:
迁移失败在 PM2 重载前中止,不中断在跑服务;与 migrationsRun 幂等共存
This commit is contained in:
2026-08-11 15:30:13 +08:00
parent d1c320b1f5
commit 30d289875b
3 changed files with 6 additions and 27 deletions

View File

@@ -1,4 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { join } from 'path';
import { APP_GUARD } from '@nestjs/core'; import { APP_GUARD } from '@nestjs/core';
import { LoggerModule } from 'nestjs-pino'; import { LoggerModule } from 'nestjs-pino';
import { ConfigModule, ConfigService } from '@nestjs/config'; import { ConfigModule, ConfigService } from '@nestjs/config';
@@ -138,6 +139,11 @@ import { IntegrationConfigModule } from './integration/config/config.module';
password: config.get<string>('DB_PASSWORD', ''), password: config.get<string>('DB_PASSWORD', ''),
database: config.get<string>('DB_DATABASE', 'dorm_billing'), database: config.get<string>('DB_DATABASE', 'dorm_billing'),
entities: allEntities, entities: allEntities,
// 官方推荐连接建立后自动执行未跑迁移migrations 表幂等)。
// ts-node 下匹配 src/migrations/*.ts编译产物下匹配 dist/migrations/*.js。
// 部署脚本的显式 migration:run 保留:迁移失败在 PM2 重载前中止,不中断在跑的服务。
migrations: [join(__dirname, 'migrations/*{.ts,.js}')],
migrationsRun: true,
// 生产安全:仅当显式 DB_SYNCHRONIZE=true 时才自动同步表结构 // 生产安全:仅当显式 DB_SYNCHRONIZE=true 时才自动同步表结构
synchronize: config.get('DB_SYNCHRONIZE') === 'true', synchronize: config.get('DB_SYNCHRONIZE') === 'true',
charset: 'utf8mb4', charset: 'utf8mb4',

View File

@@ -4,7 +4,6 @@ import { json, urlencoded } from 'express';
import helmet from 'helmet'; import helmet from 'helmet';
import compression from 'compression'; import compression from 'compression';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { runMigrationsOnStartup } from './migration-runner';
// 与 app.setGlobalPrefix('api') + ClassesController('classes') 保持同步: // 与 app.setGlobalPrefix('api') + ClassesController('classes') 保持同步:
// 花名册提交/批量导入走这里,放宽 JSON 上限;改前缀或控制器路径时需同步修改。 // 花名册提交/批量导入走这里,放宽 JSON 上限;改前缀或控制器路径时需同步修改。
@@ -13,8 +12,6 @@ const LARGE_BODY_ROUTES_PREFIX = '/api/classes';
const LARGE_BODY_LIMIT = '2mb'; const LARGE_BODY_LIMIT = '2mb';
async function bootstrap() { async function bootstrap() {
await runMigrationsOnStartup();
// 默认 express.json 上限 100kb花名册提交最多 2000 行 createRows与批量导入会超限 413 // 默认 express.json 上限 100kb花名册提交最多 2000 行 createRows与批量导入会超限 413
// 仅对 classes 路由提高上限,避免全局放宽造成大请求 DoS 面扩大 // 仅对 classes 路由提高上限,避免全局放宽造成大请求 DoS 面扩大
const app = await NestFactory.create(AppModule, { bodyParser: false }); const app = await NestFactory.create(AppModule, { bodyParser: false });

View File

@@ -1,24 +0,0 @@
import { DataSource } from 'typeorm';
import { join } from 'path';
import { config } from 'dotenv';
config();
export async function runMigrationsOnStartup(): Promise<void> {
const ds = new DataSource({
type: 'mysql',
host: process.env.DB_HOST || 'localhost',
port: Number(process.env.DB_PORT || 3306),
username: process.env.DB_USERNAME || 'root',
password: process.env.DB_PASSWORD || '',
database: process.env.DB_DATABASE || 'dorm_billing',
charset: 'utf8mb4',
// 自动发现ts-node 下匹配 src/migrations/*.ts编译产物下匹配 dist/migrations/*.js。
// 新增迁移文件无需再手改清单(此前手写数组已漏跑 2 个迁移)。
migrations: [join(__dirname, 'migrations/*{.ts,.js}')],
});
await ds.initialize();
await ds.runMigrations();
await ds.destroy();
}