first commit
This commit is contained in:
9
src/db/db.module.ts
Normal file
9
src/db/db.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { DbService } from './db.service';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [DbService],
|
||||
exports: [DbService],
|
||||
})
|
||||
export class DbModule {}
|
||||
65
src/db/db.service.ts
Normal file
65
src/db/db.service.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Pool, QueryResult, QueryResultRow } from 'pg';
|
||||
import { getIntegerConfig } from '../common/config-number';
|
||||
|
||||
type DatabaseHealth = {
|
||||
now: Date;
|
||||
timescaledb_installed: boolean;
|
||||
timescaledb_version: string | null;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class DbService implements OnModuleInit, OnModuleDestroy {
|
||||
private pool!: Pool;
|
||||
|
||||
constructor(private readonly config: ConfigService) {}
|
||||
|
||||
/** Создает пул PostgreSQL и проверяет БД до начала обработки запросов. */
|
||||
async onModuleInit(): Promise<void> {
|
||||
const connectionString = this.config.get<string>('DATABASE_URL');
|
||||
if (!connectionString) {
|
||||
throw new Error('DATABASE_URL is required.');
|
||||
}
|
||||
|
||||
this.pool = new Pool({
|
||||
connectionString,
|
||||
max: getIntegerConfig(this.config, 'PG_POOL_MAX', 20),
|
||||
idleTimeoutMillis: 30_000,
|
||||
connectionTimeoutMillis: 5_000,
|
||||
statement_timeout: 60_000,
|
||||
query_timeout: 60_000,
|
||||
application_name: 'drill-cloud-v3',
|
||||
});
|
||||
|
||||
await this.health();
|
||||
}
|
||||
|
||||
/** Закрывает пул PostgreSQL при остановке Nest-приложения. */
|
||||
async onModuleDestroy(): Promise<void> {
|
||||
await this.pool?.end();
|
||||
}
|
||||
|
||||
/** Выполняет параметризованный SQL-запрос через общий пул PostgreSQL. */
|
||||
query<T extends QueryResultRow = QueryResultRow>(
|
||||
text: string,
|
||||
values: readonly unknown[] = [],
|
||||
): Promise<QueryResult<T>> {
|
||||
return this.pool.query<T>(text, [...values]);
|
||||
}
|
||||
|
||||
/** Возвращает легкий health-снимок БД, включая статус расширения TimescaleDB. */
|
||||
async health(): Promise<DatabaseHealth> {
|
||||
const result = await this.query<DatabaseHealth>(`
|
||||
SELECT
|
||||
now(),
|
||||
ext.extversion IS NOT NULL AS timescaledb_installed,
|
||||
ext.extversion AS timescaledb_version
|
||||
FROM (SELECT 1) AS probe
|
||||
LEFT JOIN pg_extension AS ext
|
||||
ON ext.extname = 'timescaledb'
|
||||
`);
|
||||
|
||||
return result.rows[0];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user