@dofe/infra-prisma 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/db-metrics/index.d.ts +2 -0
- package/dist/db-metrics/index.d.ts.map +1 -0
- package/dist/db-metrics/index.js +18 -0
- package/dist/db-metrics/index.js.map +1 -0
- package/dist/db-metrics/src/db-metrics.module.d.ts +22 -0
- package/dist/db-metrics/src/db-metrics.module.d.ts.map +1 -0
- package/dist/db-metrics/src/db-metrics.module.js +140 -0
- package/dist/db-metrics/src/db-metrics.module.js.map +1 -0
- package/dist/db-metrics/src/db-metrics.service.d.ts +183 -0
- package/dist/db-metrics/src/db-metrics.service.d.ts.map +1 -0
- package/dist/db-metrics/src/db-metrics.service.js +334 -0
- package/dist/db-metrics/src/db-metrics.service.js.map +1 -0
- package/dist/db-metrics/src/index.d.ts +6 -0
- package/dist/db-metrics/src/index.d.ts.map +1 -0
- package/dist/db-metrics/src/index.js +24 -0
- package/dist/db-metrics/src/index.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/soft-delete.middleware.d.ts +51 -0
- package/dist/middleware/soft-delete.middleware.d.ts.map +1 -0
- package/dist/middleware/soft-delete.middleware.js +289 -0
- package/dist/middleware/soft-delete.middleware.js.map +1 -0
- package/dist/middleware/tenant-isolation-extension.d.ts +18 -0
- package/dist/middleware/tenant-isolation-extension.d.ts.map +1 -0
- package/dist/middleware/tenant-isolation-extension.js +124 -0
- package/dist/middleware/tenant-isolation-extension.js.map +1 -0
- package/dist/prisma/index.d.ts +7 -0
- package/dist/prisma/index.d.ts.map +1 -0
- package/dist/prisma/index.js +25 -0
- package/dist/prisma/index.js.map +1 -0
- package/dist/prisma/prisma.module.d.ts +3 -0
- package/dist/prisma/prisma.module.d.ts.map +1 -0
- package/dist/prisma/prisma.module.js +26 -0
- package/dist/prisma/prisma.module.js.map +1 -0
- package/dist/prisma/prisma.service.d.ts +10 -0
- package/dist/prisma/prisma.service.d.ts.map +1 -0
- package/dist/prisma/prisma.service.js +36 -0
- package/dist/prisma/prisma.service.js.map +1 -0
- package/dist/prisma/types.d.ts +4 -0
- package/dist/prisma/types.d.ts.map +1 -0
- package/dist/prisma/types.js +22 -0
- package/dist/prisma/types.js.map +1 -0
- package/dist/prisma-read/prisma-read.module.d.ts +3 -0
- package/dist/prisma-read/prisma-read.module.d.ts.map +1 -0
- package/dist/prisma-read/prisma-read.module.js +24 -0
- package/dist/prisma-read/prisma-read.module.js.map +1 -0
- package/dist/prisma-read/prisma-read.service.d.ts +47 -0
- package/dist/prisma-read/prisma-read.service.d.ts.map +1 -0
- package/dist/prisma-read/prisma-read.service.js +222 -0
- package/dist/prisma-read/prisma-read.service.js.map +1 -0
- package/dist/prisma-write/prisma-write.module.d.ts +3 -0
- package/dist/prisma-write/prisma-write.module.d.ts.map +1 -0
- package/dist/prisma-write/prisma-write.module.js +24 -0
- package/dist/prisma-write/prisma-write.module.js.map +1 -0
- package/dist/prisma-write/prisma-write.service.d.ts +47 -0
- package/dist/prisma-write/prisma-write.service.d.ts.map +1 -0
- package/dist/prisma-write/prisma-write.service.js +222 -0
- package/dist/prisma-write/prisma-write.service.js.map +1 -0
- package/dist/prometheus/index.d.ts +5 -0
- package/dist/prometheus/index.d.ts.map +1 -0
- package/dist/prometheus/index.js +9 -0
- package/dist/prometheus/index.js.map +1 -0
- package/dist/prometheus/prometheus.module.d.ts +3 -0
- package/dist/prometheus/prometheus.module.d.ts.map +1 -0
- package/dist/prometheus/prometheus.module.js +230 -0
- package/dist/prometheus/prometheus.module.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.PrismaReadModule = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const config_1 = require("@nestjs/config");
|
|
12
|
+
const db_metrics_module_1 = require("../db-metrics/src/db-metrics.module");
|
|
13
|
+
const prisma_read_service_1 = require("./prisma-read.service");
|
|
14
|
+
let PrismaReadModule = class PrismaReadModule {
|
|
15
|
+
};
|
|
16
|
+
exports.PrismaReadModule = PrismaReadModule;
|
|
17
|
+
exports.PrismaReadModule = PrismaReadModule = __decorate([
|
|
18
|
+
(0, common_1.Module)({
|
|
19
|
+
imports: [config_1.ConfigModule, db_metrics_module_1.DbMetricsModule],
|
|
20
|
+
providers: [prisma_read_service_1.PrismaReadService],
|
|
21
|
+
exports: [prisma_read_service_1.PrismaReadService],
|
|
22
|
+
})
|
|
23
|
+
], PrismaReadModule);
|
|
24
|
+
//# sourceMappingURL=prisma-read.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-read.module.js","sourceRoot":"","sources":["../../src/prisma-read/prisma-read.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2CAA8C;AAC9C,2EAAsE;AACtE,+DAA0D;AAOnD,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;CAAG,CAAA;AAAnB,4CAAgB;2BAAhB,gBAAgB;IAL5B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,qBAAY,EAAE,mCAAe,CAAC;QACxC,SAAS,EAAE,CAAC,uCAAiB,CAAC;QAC9B,OAAO,EAAE,CAAC,uCAAiB,CAAC;KAC7B,CAAC;GACW,gBAAgB,CAAG"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
import { Logger } from 'winston';
|
|
4
|
+
import { DbMetricsService } from '../db-metrics/src/db-metrics.service';
|
|
5
|
+
/**
|
|
6
|
+
* Prisma Read Service
|
|
7
|
+
* Prisma 读服务
|
|
8
|
+
*
|
|
9
|
+
* Provides read-only database access with:
|
|
10
|
+
* - Query performance monitoring
|
|
11
|
+
* - Slow query detection with configurable thresholds
|
|
12
|
+
* - Prometheus metrics integration
|
|
13
|
+
* - BigInt serialization support
|
|
14
|
+
*
|
|
15
|
+
* 提供只读数据库访问,包含:
|
|
16
|
+
* - 查询性能监控
|
|
17
|
+
* - 可配置阈值的慢查询检测
|
|
18
|
+
* - Prometheus 指标集成
|
|
19
|
+
* - BigInt 序列化支持
|
|
20
|
+
*/
|
|
21
|
+
export declare class PrismaReadService implements OnModuleInit, OnModuleDestroy {
|
|
22
|
+
private readonly logger;
|
|
23
|
+
private readonly dbMetrics?;
|
|
24
|
+
private prisma;
|
|
25
|
+
private pool;
|
|
26
|
+
constructor(logger: Logger, dbMetrics?: DbMetricsService);
|
|
27
|
+
/**
|
|
28
|
+
* Setup Prisma extensions for query monitoring and soft delete
|
|
29
|
+
* Prisma 7.x: 使用 $extends 替代 $use
|
|
30
|
+
* 设置 Prisma 扩展用于查询监控和软删除
|
|
31
|
+
*/
|
|
32
|
+
private setupExtensions;
|
|
33
|
+
/**
|
|
34
|
+
* Fallback logging when DbMetricsService is not injected
|
|
35
|
+
* 当 DbMetricsService 未注入时的回退日志记录
|
|
36
|
+
*/
|
|
37
|
+
private fallbackLog;
|
|
38
|
+
/**
|
|
39
|
+
* Get the Prisma client instance
|
|
40
|
+
* 获取 Prisma 客户端实例
|
|
41
|
+
*/
|
|
42
|
+
get client(): PrismaClient;
|
|
43
|
+
private static readonly CONNECT_TIMEOUT_MS;
|
|
44
|
+
onModuleInit(): Promise<void>;
|
|
45
|
+
onModuleDestroy(): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=prisma-read.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-read.service.d.ts","sourceRoot":"","sources":["../../src/prisma-read/prisma-read.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EACZ,eAAe,EAGhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EACL,gBAAgB,EAEjB,MAAM,sCAAsC,CAAC;AAG9C;;;;;;;;;;;;;;;GAeG;AACH,qBACa,iBAAkB,YAAW,YAAY,EAAE,eAAe;IAKlC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IALzC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,IAAI,CAAO;gBAGiC,MAAM,EAAE,MAAM,EACnC,SAAS,CAAC,EAAE,gBAAgB;IAiC3D;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAqEvB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAqCnB;;;OAGG;IACH,IAAI,MAAM,IAAI,YAAY,CAEzB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAE7C,YAAY;IAgCZ,eAAe;CAoBtB"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
var PrismaReadService_1;
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.PrismaReadService = void 0;
|
|
20
|
+
const common_1 = require("@nestjs/common");
|
|
21
|
+
const client_1 = require("@prisma/client");
|
|
22
|
+
const adapter_pg_1 = require("@prisma/adapter-pg");
|
|
23
|
+
const pg_1 = require("pg");
|
|
24
|
+
const bigint_util_1 = __importDefault(require("@dofe/infra-utils/bigint.util"));
|
|
25
|
+
const nest_winston_1 = require("nest-winston");
|
|
26
|
+
const winston_1 = require("winston");
|
|
27
|
+
const db_metrics_service_1 = require("../db-metrics/src/db-metrics.service");
|
|
28
|
+
const soft_delete_middleware_1 = require("../middleware/soft-delete.middleware");
|
|
29
|
+
/**
|
|
30
|
+
* Prisma Read Service
|
|
31
|
+
* Prisma 读服务
|
|
32
|
+
*
|
|
33
|
+
* Provides read-only database access with:
|
|
34
|
+
* - Query performance monitoring
|
|
35
|
+
* - Slow query detection with configurable thresholds
|
|
36
|
+
* - Prometheus metrics integration
|
|
37
|
+
* - BigInt serialization support
|
|
38
|
+
*
|
|
39
|
+
* 提供只读数据库访问,包含:
|
|
40
|
+
* - 查询性能监控
|
|
41
|
+
* - 可配置阈值的慢查询检测
|
|
42
|
+
* - Prometheus 指标集成
|
|
43
|
+
* - BigInt 序列化支持
|
|
44
|
+
*/
|
|
45
|
+
let PrismaReadService = class PrismaReadService {
|
|
46
|
+
static { PrismaReadService_1 = this; }
|
|
47
|
+
logger;
|
|
48
|
+
dbMetrics;
|
|
49
|
+
prisma;
|
|
50
|
+
pool;
|
|
51
|
+
constructor(logger, dbMetrics) {
|
|
52
|
+
this.logger = logger;
|
|
53
|
+
this.dbMetrics = dbMetrics;
|
|
54
|
+
// Prisma 7.x: 使用 @prisma/adapter-pg 驱动适配器
|
|
55
|
+
// 对于读写分离,优先使用 READ_DATABASE_URL
|
|
56
|
+
const connectionString = process.env.READ_DATABASE_URL || process.env.DATABASE_URL;
|
|
57
|
+
if (!connectionString) {
|
|
58
|
+
throw new Error('DATABASE_URL or READ_DATABASE_URL environment variable is not set');
|
|
59
|
+
}
|
|
60
|
+
// 创建 pg 连接池
|
|
61
|
+
this.pool = new pg_1.Pool({
|
|
62
|
+
connectionString,
|
|
63
|
+
// 连接池配置,与 Prisma 6 保持一致
|
|
64
|
+
connectionTimeoutMillis: 5000,
|
|
65
|
+
idleTimeoutMillis: 300000, // 5分钟
|
|
66
|
+
max: 10, // 最大连接数
|
|
67
|
+
});
|
|
68
|
+
// 创建 Prisma 适配器 - 直接传入 Pool 实例
|
|
69
|
+
const adapter = new adapter_pg_1.PrismaPg(this.pool);
|
|
70
|
+
// 使用适配器创建 PrismaClient
|
|
71
|
+
const basePrisma = new client_1.PrismaClient({ adapter });
|
|
72
|
+
// Prisma 7.x: 使用 $extends 替代 $use
|
|
73
|
+
// 先应用软删除扩展,再应用监控扩展
|
|
74
|
+
this.prisma = this.setupExtensions(basePrisma);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Setup Prisma extensions for query monitoring and soft delete
|
|
78
|
+
* Prisma 7.x: 使用 $extends 替代 $use
|
|
79
|
+
* 设置 Prisma 扩展用于查询监控和软删除
|
|
80
|
+
*/
|
|
81
|
+
setupExtensions(basePrisma) {
|
|
82
|
+
// 保存引用以便在回调中使用
|
|
83
|
+
const dbMetrics = this.dbMetrics;
|
|
84
|
+
const fallbackLog = this.fallbackLog.bind(this);
|
|
85
|
+
// 1. 先应用软删除扩展
|
|
86
|
+
const withSoftDelete = (0, soft_delete_middleware_1.setupSoftDeleteMiddleware)(basePrisma);
|
|
87
|
+
// 2. 应用监控扩展
|
|
88
|
+
return withSoftDelete.$extends({
|
|
89
|
+
query: {
|
|
90
|
+
async $allOperations({ operation, model, args, query }) {
|
|
91
|
+
// Start tracking
|
|
92
|
+
const ctx = dbMetrics?.recordQueryStart() ?? {
|
|
93
|
+
startTime: Date.now(),
|
|
94
|
+
traceId: 'unknown',
|
|
95
|
+
};
|
|
96
|
+
try {
|
|
97
|
+
// 执行查询并处理结果
|
|
98
|
+
const result = await query(args);
|
|
99
|
+
const serialized = bigint_util_1.default.serialize(result);
|
|
100
|
+
if (dbMetrics) {
|
|
101
|
+
dbMetrics.recordQueryEnd(ctx, {
|
|
102
|
+
model: model || 'unknown',
|
|
103
|
+
action: operation,
|
|
104
|
+
dbType: 'read',
|
|
105
|
+
}, 'success', args);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
fallbackLog(ctx.startTime, { model, action: operation, args }, 'success');
|
|
109
|
+
}
|
|
110
|
+
return serialized;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
if (dbMetrics) {
|
|
114
|
+
dbMetrics.recordQueryEnd(ctx, {
|
|
115
|
+
model: model || 'unknown',
|
|
116
|
+
action: operation,
|
|
117
|
+
dbType: 'read',
|
|
118
|
+
}, 'error', args, error);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
fallbackLog(ctx.startTime, { model, action: operation, args }, 'error', error);
|
|
122
|
+
}
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Fallback logging when DbMetricsService is not injected
|
|
131
|
+
* 当 DbMetricsService 未注入时的回退日志记录
|
|
132
|
+
*/
|
|
133
|
+
fallbackLog(startTime, params, status, error) {
|
|
134
|
+
const duration = Date.now() - startTime;
|
|
135
|
+
const logData = {
|
|
136
|
+
message: 'ReadDB Query 执行信息',
|
|
137
|
+
detail: {
|
|
138
|
+
耗时: `${duration}ms`,
|
|
139
|
+
时间: new Date().toISOString(),
|
|
140
|
+
操作: `${params.model}.${params.action}`,
|
|
141
|
+
参数: JSON.stringify(params.args),
|
|
142
|
+
状态: status,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
if (status === 'error' && error) {
|
|
146
|
+
this.logger.error({
|
|
147
|
+
...logData,
|
|
148
|
+
error: { name: error.name, message: error.message },
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
else if (duration > 1000) {
|
|
152
|
+
this.logger.warn({
|
|
153
|
+
message: 'ReadDB Query 性能警告',
|
|
154
|
+
detail: {
|
|
155
|
+
操作: `${params.model}.${params.action}`,
|
|
156
|
+
耗时: `${duration}ms`,
|
|
157
|
+
提示: '此操作的执行时间超过了1000ms,请考虑优化',
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
this.logger.info(logData);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get the Prisma client instance
|
|
167
|
+
* 获取 Prisma 客户端实例
|
|
168
|
+
*/
|
|
169
|
+
get client() {
|
|
170
|
+
return this.prisma;
|
|
171
|
+
}
|
|
172
|
+
static CONNECT_TIMEOUT_MS = 15000;
|
|
173
|
+
async onModuleInit() {
|
|
174
|
+
this.logger.info('[PrismaReadService] onModuleInit started');
|
|
175
|
+
const startedAt = Date.now();
|
|
176
|
+
this.logger.info('[PrismaReadService] Connecting to database...');
|
|
177
|
+
try {
|
|
178
|
+
await Promise.race([
|
|
179
|
+
this.prisma.$connect(),
|
|
180
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`PrismaReadService: Database connection timeout after ${PrismaReadService_1.CONNECT_TIMEOUT_MS}ms. Check DATABASE_URL and ensure PostgreSQL is running.`)), PrismaReadService_1.CONNECT_TIMEOUT_MS)),
|
|
181
|
+
]);
|
|
182
|
+
const durationMs = Date.now() - startedAt;
|
|
183
|
+
this.logger.info(`[PrismaReadService] Connected to database in ${durationMs}ms`);
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
this.logger.error('[PrismaReadService] Failed to connect to database', {
|
|
187
|
+
error: error instanceof Error ? error.message : String(error),
|
|
188
|
+
durationMs: Date.now() - startedAt,
|
|
189
|
+
});
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async onModuleDestroy() {
|
|
194
|
+
try {
|
|
195
|
+
await this.prisma.$disconnect();
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
this.logger.warn('Error disconnecting Prisma client', { error });
|
|
199
|
+
}
|
|
200
|
+
// 检查 pool 是否已经关闭,避免重复调用 end()
|
|
201
|
+
if (this.pool && !this.pool.ended) {
|
|
202
|
+
try {
|
|
203
|
+
await this.pool.end();
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
this.logger.warn('Error closing database pool', { error });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (process.env.NODE_ENV?.startsWith('prod')) {
|
|
210
|
+
this.logger.info('PrismaReadService disconnected from database');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
exports.PrismaReadService = PrismaReadService;
|
|
215
|
+
exports.PrismaReadService = PrismaReadService = PrismaReadService_1 = __decorate([
|
|
216
|
+
(0, common_1.Injectable)(),
|
|
217
|
+
__param(0, (0, common_1.Inject)(nest_winston_1.WINSTON_MODULE_PROVIDER)),
|
|
218
|
+
__param(1, (0, common_1.Optional)()),
|
|
219
|
+
__metadata("design:paramtypes", [winston_1.Logger,
|
|
220
|
+
db_metrics_service_1.DbMetricsService])
|
|
221
|
+
], PrismaReadService);
|
|
222
|
+
//# sourceMappingURL=prisma-read.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-read.service.js","sourceRoot":"","sources":["../../src/prisma-read/prisma-read.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-write.module.d.ts","sourceRoot":"","sources":["../../src/prisma-write/prisma-write.module.ts"],"names":[],"mappings":"AAKA,qBAKa,iBAAiB;CAAG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.PrismaWriteModule = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const prisma_write_service_1 = require("./prisma-write.service");
|
|
12
|
+
const config_1 = require("@nestjs/config");
|
|
13
|
+
const db_metrics_module_1 = require("../db-metrics/src/db-metrics.module");
|
|
14
|
+
let PrismaWriteModule = class PrismaWriteModule {
|
|
15
|
+
};
|
|
16
|
+
exports.PrismaWriteModule = PrismaWriteModule;
|
|
17
|
+
exports.PrismaWriteModule = PrismaWriteModule = __decorate([
|
|
18
|
+
(0, common_1.Module)({
|
|
19
|
+
imports: [config_1.ConfigModule, db_metrics_module_1.DbMetricsModule],
|
|
20
|
+
providers: [prisma_write_service_1.PrismaWriteService],
|
|
21
|
+
exports: [prisma_write_service_1.PrismaWriteService],
|
|
22
|
+
})
|
|
23
|
+
], PrismaWriteModule);
|
|
24
|
+
//# sourceMappingURL=prisma-write.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-write.module.js","sourceRoot":"","sources":["../../src/prisma-write/prisma-write.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,iEAA4D;AAC5D,2CAA8C;AAC9C,2EAAsE;AAO/D,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;CAAG,CAAA;AAApB,8CAAiB;4BAAjB,iBAAiB;IAL7B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,qBAAY,EAAE,mCAAe,CAAC;QACxC,SAAS,EAAE,CAAC,yCAAkB,CAAC;QAC/B,OAAO,EAAE,CAAC,yCAAkB,CAAC;KAC9B,CAAC;GACW,iBAAiB,CAAG"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
import { Logger } from 'winston';
|
|
3
|
+
import { PrismaClient } from '@prisma/client';
|
|
4
|
+
import { DbMetricsService } from '../db-metrics/src/db-metrics.service';
|
|
5
|
+
/**
|
|
6
|
+
* Prisma Write Service
|
|
7
|
+
* Prisma 写服务
|
|
8
|
+
*
|
|
9
|
+
* Provides write database access with:
|
|
10
|
+
* - Query performance monitoring
|
|
11
|
+
* - Slow query detection with configurable thresholds
|
|
12
|
+
* - Prometheus metrics integration
|
|
13
|
+
* - BigInt serialization support
|
|
14
|
+
*
|
|
15
|
+
* 提供写数据库访问,包含:
|
|
16
|
+
* - 查询性能监控
|
|
17
|
+
* - 可配置阈值的慢查询检测
|
|
18
|
+
* - Prometheus 指标集成
|
|
19
|
+
* - BigInt 序列化支持
|
|
20
|
+
*/
|
|
21
|
+
export declare class PrismaWriteService implements OnModuleInit, OnModuleDestroy {
|
|
22
|
+
private readonly logger;
|
|
23
|
+
private readonly dbMetrics?;
|
|
24
|
+
private prisma;
|
|
25
|
+
private pool;
|
|
26
|
+
constructor(logger: Logger, dbMetrics?: DbMetricsService);
|
|
27
|
+
/**
|
|
28
|
+
* Setup Prisma extensions for query monitoring and soft delete
|
|
29
|
+
* Prisma 7.x: 使用 $extends 替代 $use
|
|
30
|
+
* 设置 Prisma 扩展用于查询监控和软删除
|
|
31
|
+
*/
|
|
32
|
+
private setupExtensions;
|
|
33
|
+
/**
|
|
34
|
+
* Fallback logging when DbMetricsService is not injected
|
|
35
|
+
* 当 DbMetricsService 未注入时的回退日志记录
|
|
36
|
+
*/
|
|
37
|
+
private fallbackLog;
|
|
38
|
+
/**
|
|
39
|
+
* Get the Prisma client instance
|
|
40
|
+
* 获取 Prisma 客户端实例
|
|
41
|
+
*/
|
|
42
|
+
get client(): PrismaClient;
|
|
43
|
+
private static readonly CONNECT_TIMEOUT_MS;
|
|
44
|
+
onModuleInit(): Promise<void>;
|
|
45
|
+
onModuleDestroy(): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=prisma-write.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-write.service.d.ts","sourceRoot":"","sources":["../../src/prisma-write/prisma-write.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EACZ,eAAe,EAGhB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK9C,OAAO,EACL,gBAAgB,EAEjB,MAAM,sCAAsC,CAAC;AAE9C;;;;;;;;;;;;;;;GAeG;AACH,qBACa,kBAAmB,YAAW,YAAY,EAAE,eAAe;IAKnC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IALzC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,IAAI,CAAO;gBAGiC,MAAM,EAAE,MAAM,EACnC,SAAS,CAAC,EAAE,gBAAgB;IA6B3D;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAqEvB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAqCnB;;;OAGG;IACH,IAAI,MAAM,IAAI,YAAY,CAEzB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAE7C,YAAY;IAgCZ,eAAe;CAoBtB"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
var PrismaWriteService_1;
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.PrismaWriteService = void 0;
|
|
20
|
+
const common_1 = require("@nestjs/common");
|
|
21
|
+
const nest_winston_1 = require("nest-winston");
|
|
22
|
+
const winston_1 = require("winston");
|
|
23
|
+
const client_1 = require("@prisma/client");
|
|
24
|
+
const adapter_pg_1 = require("@prisma/adapter-pg");
|
|
25
|
+
const pg_1 = require("pg");
|
|
26
|
+
const bigint_util_1 = __importDefault(require("@dofe/infra-utils/bigint.util"));
|
|
27
|
+
const soft_delete_middleware_1 = require("../middleware/soft-delete.middleware");
|
|
28
|
+
const db_metrics_service_1 = require("../db-metrics/src/db-metrics.service");
|
|
29
|
+
/**
|
|
30
|
+
* Prisma Write Service
|
|
31
|
+
* Prisma 写服务
|
|
32
|
+
*
|
|
33
|
+
* Provides write database access with:
|
|
34
|
+
* - Query performance monitoring
|
|
35
|
+
* - Slow query detection with configurable thresholds
|
|
36
|
+
* - Prometheus metrics integration
|
|
37
|
+
* - BigInt serialization support
|
|
38
|
+
*
|
|
39
|
+
* 提供写数据库访问,包含:
|
|
40
|
+
* - 查询性能监控
|
|
41
|
+
* - 可配置阈值的慢查询检测
|
|
42
|
+
* - Prometheus 指标集成
|
|
43
|
+
* - BigInt 序列化支持
|
|
44
|
+
*/
|
|
45
|
+
let PrismaWriteService = class PrismaWriteService {
|
|
46
|
+
static { PrismaWriteService_1 = this; }
|
|
47
|
+
logger;
|
|
48
|
+
dbMetrics;
|
|
49
|
+
prisma;
|
|
50
|
+
pool;
|
|
51
|
+
constructor(logger, dbMetrics) {
|
|
52
|
+
this.logger = logger;
|
|
53
|
+
this.dbMetrics = dbMetrics;
|
|
54
|
+
// Prisma 7.x: 使用 @prisma/adapter-pg 驱动适配器
|
|
55
|
+
const connectionString = process.env.DATABASE_URL;
|
|
56
|
+
if (!connectionString) {
|
|
57
|
+
throw new Error('DATABASE_URL environment variable is not set');
|
|
58
|
+
}
|
|
59
|
+
// 创建 pg 连接池
|
|
60
|
+
this.pool = new pg_1.Pool({
|
|
61
|
+
connectionString,
|
|
62
|
+
// 连接池配置,与 Prisma 6 保持一致
|
|
63
|
+
connectionTimeoutMillis: 5000,
|
|
64
|
+
idleTimeoutMillis: 300000, // 5分钟
|
|
65
|
+
max: 20, // 写操作使用更大的连接池
|
|
66
|
+
});
|
|
67
|
+
// 创建 Prisma 适配器 - 直接传入 Pool 实例
|
|
68
|
+
const adapter = new adapter_pg_1.PrismaPg(this.pool);
|
|
69
|
+
// 使用适配器创建 PrismaClient
|
|
70
|
+
const basePrisma = new client_1.PrismaClient({ adapter });
|
|
71
|
+
// Prisma 7.x: 使用 $extends 替代 $use
|
|
72
|
+
// 先应用软删除扩展,再应用监控扩展
|
|
73
|
+
this.prisma = this.setupExtensions(basePrisma);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Setup Prisma extensions for query monitoring and soft delete
|
|
77
|
+
* Prisma 7.x: 使用 $extends 替代 $use
|
|
78
|
+
* 设置 Prisma 扩展用于查询监控和软删除
|
|
79
|
+
*/
|
|
80
|
+
setupExtensions(basePrisma) {
|
|
81
|
+
// 保存引用以便在回调中使用
|
|
82
|
+
const dbMetrics = this.dbMetrics;
|
|
83
|
+
const fallbackLog = this.fallbackLog.bind(this);
|
|
84
|
+
// 1. 先应用软删除扩展
|
|
85
|
+
const withSoftDelete = (0, soft_delete_middleware_1.setupSoftDeleteMiddleware)(basePrisma);
|
|
86
|
+
// 2. 应用监控扩展
|
|
87
|
+
return withSoftDelete.$extends({
|
|
88
|
+
query: {
|
|
89
|
+
async $allOperations({ operation, model, args, query }) {
|
|
90
|
+
// Start tracking
|
|
91
|
+
const ctx = dbMetrics?.recordQueryStart() ?? {
|
|
92
|
+
startTime: Date.now(),
|
|
93
|
+
traceId: 'unknown',
|
|
94
|
+
};
|
|
95
|
+
try {
|
|
96
|
+
// 执行查询并处理结果
|
|
97
|
+
const result = await query(args);
|
|
98
|
+
const serialized = bigint_util_1.default.serialize(result);
|
|
99
|
+
if (dbMetrics) {
|
|
100
|
+
dbMetrics.recordQueryEnd(ctx, {
|
|
101
|
+
model: model || 'unknown',
|
|
102
|
+
action: operation,
|
|
103
|
+
dbType: 'write',
|
|
104
|
+
}, 'success', args);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
fallbackLog(ctx.startTime, { model, action: operation, args }, 'success');
|
|
108
|
+
}
|
|
109
|
+
return serialized;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (dbMetrics) {
|
|
113
|
+
dbMetrics.recordQueryEnd(ctx, {
|
|
114
|
+
model: model || 'unknown',
|
|
115
|
+
action: operation,
|
|
116
|
+
dbType: 'write',
|
|
117
|
+
}, 'error', args, error);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
fallbackLog(ctx.startTime, { model, action: operation, args }, 'error', error);
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Fallback logging when DbMetricsService is not injected
|
|
130
|
+
* 当 DbMetricsService 未注入时的回退日志记录
|
|
131
|
+
*/
|
|
132
|
+
fallbackLog(startTime, params, status, error) {
|
|
133
|
+
const duration = Date.now() - startTime;
|
|
134
|
+
const logData = {
|
|
135
|
+
message: 'WriteDB Query 执行信息',
|
|
136
|
+
detail: {
|
|
137
|
+
耗时: `${duration}ms`,
|
|
138
|
+
时间: new Date().toISOString(),
|
|
139
|
+
操作: `${params.model}.${params.action}`,
|
|
140
|
+
参数: JSON.stringify(params.args),
|
|
141
|
+
状态: status,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
if (status === 'error' && error) {
|
|
145
|
+
this.logger.error({
|
|
146
|
+
...logData,
|
|
147
|
+
error: { name: error.name, message: error.message },
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
else if (duration > 1000) {
|
|
151
|
+
this.logger.warn({
|
|
152
|
+
message: 'WriteDB Query 性能警告',
|
|
153
|
+
detail: {
|
|
154
|
+
操作: `${params.model}.${params.action}`,
|
|
155
|
+
耗时: `${duration}ms`,
|
|
156
|
+
提示: '此操作的执行时间超过了1000ms,请考虑优化',
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this.logger.info(logData);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get the Prisma client instance
|
|
166
|
+
* 获取 Prisma 客户端实例
|
|
167
|
+
*/
|
|
168
|
+
get client() {
|
|
169
|
+
return this.prisma;
|
|
170
|
+
}
|
|
171
|
+
static CONNECT_TIMEOUT_MS = 15000;
|
|
172
|
+
async onModuleInit() {
|
|
173
|
+
this.logger.info('[PrismaWriteService] onModuleInit started');
|
|
174
|
+
const startedAt = Date.now();
|
|
175
|
+
this.logger.info('[PrismaWriteService] Connecting to database...');
|
|
176
|
+
try {
|
|
177
|
+
await Promise.race([
|
|
178
|
+
this.prisma.$connect(),
|
|
179
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`PrismaWriteService: Database connection timeout after ${PrismaWriteService_1.CONNECT_TIMEOUT_MS}ms. Check DATABASE_URL and ensure PostgreSQL is running.`)), PrismaWriteService_1.CONNECT_TIMEOUT_MS)),
|
|
180
|
+
]);
|
|
181
|
+
const durationMs = Date.now() - startedAt;
|
|
182
|
+
this.logger.info(`[PrismaWriteService] Connected to database in ${durationMs}ms`);
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
this.logger.error('[PrismaWriteService] Failed to connect to database', {
|
|
186
|
+
error: error instanceof Error ? error.message : String(error),
|
|
187
|
+
durationMs: Date.now() - startedAt,
|
|
188
|
+
});
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async onModuleDestroy() {
|
|
193
|
+
try {
|
|
194
|
+
await this.prisma.$disconnect();
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
this.logger.warn('Error disconnecting Prisma client', { error });
|
|
198
|
+
}
|
|
199
|
+
// 检查 pool 是否已经关闭,避免重复调用 end()
|
|
200
|
+
if (this.pool && !this.pool.ended) {
|
|
201
|
+
try {
|
|
202
|
+
await this.pool.end();
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
this.logger.warn('Error closing database pool', { error });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (process.env.NODE_ENV?.startsWith('prod')) {
|
|
209
|
+
this.logger.info('PrismaWriteService disconnected from database');
|
|
210
|
+
}
|
|
211
|
+
// this.logger.info('PrismaWriteService disconnected from database');
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
exports.PrismaWriteService = PrismaWriteService;
|
|
215
|
+
exports.PrismaWriteService = PrismaWriteService = PrismaWriteService_1 = __decorate([
|
|
216
|
+
(0, common_1.Injectable)(),
|
|
217
|
+
__param(0, (0, common_1.Inject)(nest_winston_1.WINSTON_MODULE_PROVIDER)),
|
|
218
|
+
__param(1, (0, common_1.Optional)()),
|
|
219
|
+
__metadata("design:paramtypes", [winston_1.Logger,
|
|
220
|
+
db_metrics_service_1.DbMetricsService])
|
|
221
|
+
], PrismaWriteService);
|
|
222
|
+
//# sourceMappingURL=prisma-write.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-write.service.js","sourceRoot":"","sources":["../../src/prisma-write/prisma-write.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prometheus/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PrometheusConfigModule = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Prometheus 模块导出
|
|
6
|
+
*/
|
|
7
|
+
var prometheus_module_1 = require("./prometheus.module");
|
|
8
|
+
Object.defineProperty(exports, "PrometheusConfigModule", { enumerable: true, get: function () { return prometheus_module_1.PrometheusConfigModule; } });
|
|
9
|
+
//# sourceMappingURL=index.js.map
|