diff --git a/src/core/configs/dist/typeorm.oracle.config.js b/src/core/configs/dist/typeorm.oracle.config.js deleted file mode 100644 index 19252c7..0000000 --- a/src/core/configs/dist/typeorm.oracle.config.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; -exports.__esModule = true; -exports.createOracleConfig = void 0; -var oracledb = require("oracledb"); -// Inicializar o cliente Oracle -oracledb.initOracleClient({ libDir: "C:\\oracle" }); -// Definir a estratégia de pool padrão para Oracle -oracledb.poolTimeout = 60; // timeout do pool em segundos -oracledb.queueTimeout = 60000; // timeout da fila em milissegundos -oracledb.poolIncrement = 1; // incremental de conexões -function createOracleConfig(config) { - // Obter configurações de ambiente ou usar valores padrão - var poolMin = parseInt(config.get('ORACLE_POOL_MIN', '5')); - var poolMax = parseInt(config.get('ORACLE_POOL_MAX', '20')); - var poolIncrement = parseInt(config.get('ORACLE_POOL_INCREMENT', '5')); - var poolTimeout = parseInt(config.get('ORACLE_POOL_TIMEOUT', '30000')); - var idleTimeout = parseInt(config.get('ORACLE_POOL_IDLE_TIMEOUT', '300000')); - // Validação de valores mínimos - var validPoolMin = Math.max(1, poolMin); - var validPoolMax = Math.max(validPoolMin + 1, poolMax); - var validPoolIncrement = Math.max(1, poolIncrement); - // Certifique-se de que poolMax é maior que poolMin - if (validPoolMax <= validPoolMin) { - console.warn('Warning: poolMax deve ser maior que poolMin. Ajustando poolMax para poolMin + 1'); - } - var options = { - type: 'oracle', - connectString: config.get('ORACLE_CONNECT_STRING'), - username: config.get('ORACLE_USER'), - password: config.get('ORACLE_PASSWORD'), - synchronize: false, - logging: config.get('NODE_ENV') === 'development', - entities: [__dirname + '/../**/*.entity.{ts,js}'], - extra: { - // Configurações de pool - poolMin: validPoolMin, - poolMax: validPoolMax, - poolIncrement: validPoolIncrement, - poolTimeout: Math.floor(poolTimeout / 1000), - queueTimeout: 60000, - enableStats: true, - homogeneous: true, - poolPingInterval: 60, - stmtCacheSize: 30, - connectionClass: 'PORTALJURU', - idleTimeout: Math.floor(idleTimeout / 1000) - } - }; - return options; -} -exports.createOracleConfig = createOracleConfig; diff --git a/src/core/configs/dist/typeorm.postgres.config.js b/src/core/configs/dist/typeorm.postgres.config.js deleted file mode 100644 index 753ded0..0000000 --- a/src/core/configs/dist/typeorm.postgres.config.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; -exports.__esModule = true; -exports.createPostgresConfig = void 0; -function createPostgresConfig(config) { - // Obter configurações de ambiente ou usar valores padrão - var poolMin = parseInt(config.get('POSTGRES_POOL_MIN', '5')); - var poolMax = parseInt(config.get('POSTGRES_POOL_MAX', '20')); - var idleTimeout = parseInt(config.get('POSTGRES_POOL_IDLE_TIMEOUT', '30000')); - var connectionTimeout = parseInt(config.get('POSTGRES_POOL_CONNECTION_TIMEOUT', '5000')); - var acquireTimeout = parseInt(config.get('POSTGRES_POOL_ACQUIRE_TIMEOUT', '60000')); - // Validação de valores mínimos - var validPoolMin = Math.max(1, poolMin); - var validPoolMax = Math.max(validPoolMin + 1, poolMax); - var validIdleTimeout = Math.max(1000, idleTimeout); - var validConnectionTimeout = Math.max(1000, connectionTimeout); - var validAcquireTimeout = Math.max(1000, acquireTimeout); - var options = { - type: 'postgres', - host: config.get('POSTGRES_HOST'), - port: parseInt(config.get('POSTGRES_PORT', '5432')), - username: config.get('POSTGRES_USER'), - password: config.get('POSTGRES_PASSWORD'), - database: config.get('POSTGRES_DB'), - synchronize: config.get('NODE_ENV') === 'development', - entities: [__dirname + '/../**/*.entity.{ts,js}'], - ssl: config.get('NODE_ENV') === 'production' ? { rejectUnauthorized: false } : false, - logging: config.get('NODE_ENV') === 'development', - poolSize: validPoolMax, - extra: { - // Configuração de pool do PostgreSQL - min: validPoolMin, - max: validPoolMax, - idleTimeoutMillis: validIdleTimeout, - connectionTimeoutMillis: validConnectionTimeout, - acquireTimeoutMillis: validAcquireTimeout, - statement_timeout: 10000, - query_timeout: 10000 - }, - cache: { - duration: 60000 - } - }; - return options; -} -exports.createPostgresConfig = createPostgresConfig; diff --git a/src/health/indicators/db-pool-stats.health.ts b/src/health/indicators/db-pool-stats.health.ts index d7407bc..b93514b 100644 --- a/src/health/indicators/db-pool-stats.health.ts +++ b/src/health/indicators/db-pool-stats.health.ts @@ -1,84 +1,193 @@ -import { Injectable } from '@nestjs/common'; -import { HealthIndicator, HealthIndicatorResult } from '@nestjs/terminus'; +import { Injectable, Logger } from '@nestjs/common'; +import { + HealthIndicator, + HealthIndicatorResult, + HealthCheckError, // Import HealthCheckError for better terminus integration +} from '@nestjs/terminus'; import { InjectConnection } from '@nestjs/typeorm'; import { DataSource } from 'typeorm'; +const ORACLE_HEALTH_KEY = 'oracle_pool_stats'; +const POSTGRES_HEALTH_KEY = 'postgres_pool_stats'; +const ORACLE_PROGRAM_PATTERN = 'node%'; // Default pattern for Oracle +const POSTGRES_APP_NAME_PATTERN = 'nodejs%'; // Default pattern for PostgreSQL + @Injectable() export class DbPoolStatsIndicator extends HealthIndicator { + private readonly logger = new Logger(DbPoolStatsIndicator.name); + constructor( - @InjectConnection('oracle') private oracleConnection: DataSource, - @InjectConnection('postgres') private postgresConnection: DataSource, + + @InjectConnection('oracle') private readonly oracleDataSource: DataSource, + @InjectConnection('postgres') private readonly postgresDataSource: DataSource, ) { super(); } - async checkOraclePoolStats(): Promise { - const key = 'oracle_pool'; - + /** +* Verifica a integridade do pool de conexões Oracle consultando V$SESSION. +* Observações: Requer privilégios SELECT em V$SESSION e depende da coluna PROGRAM. +* Isso verifica principalmente a acessibilidade do banco de dados e o sucesso da execução da consulta. +* Considere estatísticas de pool em nível de driver para obter uma integridade de pool mais precisa, se disponível. + * + * @param key Custom key for the health indicator component. + * @param programLike Optional pattern to match the PROGRAM column in V$SESSION. + */ + async checkOraclePoolStats( + key: string = ORACLE_HEALTH_KEY, + programLike: string = ORACLE_PROGRAM_PATTERN, + ): Promise { try { - const queryResult = await this.oracleConnection.query(` - SELECT - 'ORACLEDB_POOL' as source, - COUNT(*) as total_connections - FROM - V$SESSION - WHERE - TYPE = 'USER' - AND PROGRAM LIKE 'nodejs%' - `); +// Usar parâmetros de consulta é uma boa prática, embora menos crítica para LIKE com um padrão fixo. +// Oracle usa a sintaxe :paramName + const query = ` + SELECT + COUNT(*) AS "totalConnections" -- Use quoted identifiers if needed, or match case below + FROM + V$SESSION + WHERE + TYPE = 'USER' + AND PROGRAM LIKE :pattern + `; + const params = { pattern: programLike }; - const status = { - isHealthy: true, - totalConnections: queryResult?.[0]?.total_connections || 0, - connectionClass: 'PORTALJURU', + const results: { totalConnections: number | string }[] = + await this.oracleDataSource.query(query, [params.pattern]); // Pass parameters as an array for Oracle usually + + if (!results || results.length === 0) { + this.logger.warn(`Oracle V$SESSION query returned no results for pattern '${programLike}'`); + + } + + const totalConnections = parseInt(String(results?.[0]?.totalConnections ?? 0), 10); + + if (isNaN(totalConnections)) { + throw new Error('Failed to parse totalConnections from Oracle V$SESSION query result.'); + } +// isHealthy é verdadeiro se a consulta for executada sem gerar um erro. +// Adicione lógica aqui se contagens de conexão específicas indicarem estado não íntegro (por exemplo, > poolMax) + const isHealthy = true; + const details = { + totalConnections: totalConnections, + programPattern: programLike, }; - return this.getStatus(key, status.isHealthy, { - totalConnections: status.totalConnections, - connectionClass: status.connectionClass, - }); + return this.getStatus(key, isHealthy, details); + } catch (error) { - // Em caso de erro, ainda retornar um status (não saudável) - return this.getStatus(key, false, { - message: `Erro ao obter estatísticas do pool Oracle: ${error.message}`, - }); + this.logger.error(`Oracle pool stats check failed for key "${key}": ${error.message}`, error.stack); + throw new HealthCheckError( + `${key} check failed`, + this.getStatus(key, false, { message: error.message }), + ); } } - async checkPostgresPoolStats(): Promise { - const key = 'postgres_pool'; - + /** +* Verifica a integridade do pool de conexões do PostgreSQL consultando pg_stat_activity. +* Observações: Depende de o application_name estar definido corretamente na string de conexão ou nas opções. +* Isso verifica principalmente a acessibilidade do banco de dados e o sucesso da execução da consulta. +* Considere estatísticas de pool em nível de driver para obter uma integridade de pool mais precisa, se disponível. + * + * @param key Custom key for the health indicator component. + * @param appNameLike Optional pattern to match the application_name column. + */ + async checkPostgresPoolStats( + key: string = POSTGRES_HEALTH_KEY, + appNameLike: string = POSTGRES_APP_NAME_PATTERN, + ): Promise { try { - // Obter estatísticas do pool PostgreSQL - const queryResult = await this.postgresConnection.query(` - SELECT - count(*) as total_connections, - sum(CASE WHEN state = 'active' THEN 1 ELSE 0 END) as active_connections, - sum(CASE WHEN state = 'idle' THEN 1 ELSE 0 END) as idle_connections - FROM - pg_stat_activity - WHERE + const query = ` + SELECT + count(*) AS "totalConnections", + sum(CASE WHEN state = 'active' THEN 1 ELSE 0 END) AS "activeConnections", + sum(CASE WHEN state = 'idle' THEN 1 ELSE 0 END) AS "idleConnections", + sum(CASE WHEN state = 'idle in transaction' THEN 1 ELSE 0 END) AS "idleInTransactionConnections" + FROM + pg_stat_activity + WHERE datname = current_database() - AND application_name LIKE 'nodejs%' - `); + AND application_name LIKE $1 + `; + const params = [appNameLike]; - const status = { - isHealthy: true, - totalConnections: parseInt(queryResult?.[0]?.total_connections) || 0, - activeConnections: parseInt(queryResult?.[0]?.active_connections) || 0, - idleConnections: parseInt(queryResult?.[0]?.idle_connections) || 0, + const results: { + totalConnections: string | number; + activeConnections: string | number; + idleConnections: string | number; + idleInTransactionConnections: string | number; + }[] = await this.postgresDataSource.query(query, params); + + + if (!results || results.length === 0) { + + throw new Error('PostgreSQL pg_stat_activity query returned no results unexpectedly.'); + } + + const result = results[0]; + + const totalConnections = parseInt(String(result.totalConnections ?? 0), 10); + const activeConnections = parseInt(String(result.activeConnections ?? 0), 10); + const idleConnections = parseInt(String(result.idleConnections ?? 0), 10); + const idleInTransactionConnections = parseInt(String(result.idleInTransactionConnections ?? 0), 10); + + // Validate parsing + if (isNaN(totalConnections) || isNaN(activeConnections) || isNaN(idleConnections) || isNaN(idleInTransactionConnections)) { + throw new Error('Failed to parse connection counts from PostgreSQL pg_stat_activity query result.'); + } + + + const isHealthy = true; + const details = { + totalConnections, + activeConnections, + idleConnections, + idleInTransactionConnections, + applicationNamePattern: appNameLike, }; - return this.getStatus(key, status.isHealthy, { - totalConnections: status.totalConnections, - activeConnections: status.activeConnections, - idleConnections: status.idleConnections, - }); + return this.getStatus(key, isHealthy, details); + } catch (error) { - // Em caso de erro, ainda retornar um status (não saudável) - return this.getStatus(key, false, { - message: `Erro ao obter estatísticas do pool PostgreSQL: ${error.message}`, - }); + this.logger.error(`PostgreSQL pool stats check failed for key "${key}": ${error.message}`, error.stack); + + throw new HealthCheckError( + `${key} check failed`, + this.getStatus(key, false, { message: error.message }), + ); } } -} \ No newline at end of file + + /** + * Convenience method to run all pool checks defined in this indicator. + * You would typically call this from your main HealthController. + */ + async checkAllPools() : Promise { + const results = await Promise.allSettled([ + this.checkOraclePoolStats(), + this.checkPostgresPoolStats() + ]); + + // Processa os resultados para se ajustar à estrutura do Terminus, se necessário, ou retorna diretamente +// Observações: Métodos individuais já retornam HealthIndicatorResult ou lançam HealthCheckError +// Este método pode não ser estritamente necessário se você chamar verificações individuais no controlador. +// Para simplificar, vamos supor que o controlador chama as verificações individuais. +// Se você quisesse que esse método retornasse um único status, precisaria de mais lógica. +// Relançar erros ou agregar status. + + // Example: Log results (individual methods handle the Terminus return/error) + results.forEach(result => { + if (result.status === 'rejected') { + // Already logged and thrown as HealthCheckError inside the check methods + } else { + // Optionally log success details + this.logger.log(`Pool check successful: ${JSON.stringify(result.value)}`); + } + }); + + + return results + .filter((r): r is PromiseFulfilledResult => r.status === 'fulfilled') + .map(r => r.value); + } +} \ No newline at end of file diff --git a/src/health/indicators/typeorm.health.ts b/src/health/indicators/typeorm.health.ts index 6eb559d..5c1c165 100644 --- a/src/health/indicators/typeorm.health.ts +++ b/src/health/indicators/typeorm.health.ts @@ -16,7 +16,6 @@ export class TypeOrmHealthIndicator extends HealthIndicator { const key = 'oracle'; try { - // Verifica se a conexão com Oracle está funcionando const isHealthy = this.oracleConnection.isInitialized; const result = this.getStatus(key, isHealthy); @@ -27,7 +26,6 @@ export class TypeOrmHealthIndicator extends HealthIndicator { throw new HealthCheckError('Oracle healthcheck failed', result); } catch (error) { - // Se houver qualquer erro, consideramos a conexão como não saudável const result = this.getStatus(key, false, { message: error.message }); throw new HealthCheckError('Oracle healthcheck failed', result); } @@ -37,7 +35,6 @@ export class TypeOrmHealthIndicator extends HealthIndicator { const key = 'postgres'; try { - // Verifica se a conexão com Postgres está funcionando const isHealthy = this.postgresConnection.isInitialized; const result = this.getStatus(key, isHealthy); @@ -48,7 +45,6 @@ export class TypeOrmHealthIndicator extends HealthIndicator { throw new HealthCheckError('Postgres healthcheck failed', result); } catch (error) { - // Se houver qualquer erro, consideramos a conexão como não saudável const result = this.getStatus(key, false, { message: error.message }); throw new HealthCheckError('Postgres healthcheck failed', result); } diff --git a/src/orders/modules/dist/orders.module.js b/src/orders/modules/dist/orders.module.js deleted file mode 100644 index 87a597b..0000000 --- a/src/orders/modules/dist/orders.module.js +++ /dev/null @@ -1,32 +0,0 @@ -"use strict"; -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - 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; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -exports.__esModule = true; -exports.OrdersModule = void 0; -var common_1 = require("@nestjs/common"); -var orders_controller_1 = require("../controllers/orders.controller"); -var orders_service_1 = require("../application/orders.service"); -var orders_repository_1 = require("../repositories/orders.repository"); -var database_module_1 = require("../../core/database/database.module"); -var config_1 = require("@nestjs/config"); -var OrdersModule = /** @class */ (function () { - function OrdersModule() { - } - OrdersModule = __decorate([ - common_1.Module({ - imports: [ - config_1.ConfigModule, - database_module_1.DatabaseModule, - ], - controllers: [orders_controller_1.OrdersController], - providers: [orders_service_1.OrdersService, orders_repository_1.OrdersRepository], - exports: [orders_service_1.OrdersService] - }) - ], OrdersModule); - return OrdersModule; -}()); -exports.OrdersModule = OrdersModule;