제어관리 외부 커넥션 설정기능
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import { Client } from 'pg';
|
||||
import { DatabaseConnector, ConnectionConfig, QueryResult } from '../interfaces/DatabaseConnector';
|
||||
import { ConnectionTestResult, TableInfo } from '../types/externalDbTypes';
|
||||
import { Client } from "pg";
|
||||
import {
|
||||
DatabaseConnector,
|
||||
ConnectionConfig,
|
||||
QueryResult,
|
||||
} from "../interfaces/DatabaseConnector";
|
||||
import { ConnectionTestResult, TableInfo } from "../types/externalDbTypes";
|
||||
|
||||
export class PostgreSQLConnector implements DatabaseConnector {
|
||||
private client: Client | null = null;
|
||||
@@ -11,37 +15,72 @@ export class PostgreSQLConnector implements DatabaseConnector {
|
||||
}
|
||||
|
||||
async connect(): Promise<void> {
|
||||
if (this.client) {
|
||||
await this.disconnect();
|
||||
}
|
||||
// 기존 연결이 있다면 먼저 정리
|
||||
await this.forceDisconnect();
|
||||
|
||||
const clientConfig: any = {
|
||||
host: this.config.host,
|
||||
port: this.config.port,
|
||||
database: this.config.database,
|
||||
user: this.config.user,
|
||||
password: this.config.password,
|
||||
// 연결 안정성 개선 (더 보수적인 설정)
|
||||
connectionTimeoutMillis: this.config.connectionTimeoutMillis || 15000,
|
||||
query_timeout: this.config.queryTimeoutMillis || 20000,
|
||||
keepAlive: false, // keepAlive 비활성화 (연결 문제 방지)
|
||||
// SASL 인증 문제 방지
|
||||
application_name: "PLM-ERP-System",
|
||||
// 추가 안정성 설정
|
||||
statement_timeout: 20000,
|
||||
idle_in_transaction_session_timeout: 30000,
|
||||
};
|
||||
|
||||
if (this.config.connectionTimeoutMillis != null) {
|
||||
clientConfig.connectionTimeoutMillis = this.config.connectionTimeoutMillis;
|
||||
}
|
||||
|
||||
if (this.config.queryTimeoutMillis != null) {
|
||||
clientConfig.query_timeout = this.config.queryTimeoutMillis;
|
||||
}
|
||||
|
||||
if (this.config.ssl != null) {
|
||||
clientConfig.ssl = this.config.ssl;
|
||||
}
|
||||
|
||||
this.client = new Client(clientConfig);
|
||||
await this.client.connect();
|
||||
|
||||
// 연결 시 더 긴 타임아웃 설정
|
||||
const connectPromise = this.client.connect();
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error("연결 타임아웃")), 20000);
|
||||
});
|
||||
|
||||
await Promise.race([connectPromise, timeoutPromise]);
|
||||
console.log(
|
||||
`✅ PostgreSQL 연결 성공: ${this.config.host}:${this.config.port}`
|
||||
);
|
||||
}
|
||||
|
||||
// 강제 연결 해제 메서드 추가
|
||||
private async forceDisconnect(): Promise<void> {
|
||||
if (this.client) {
|
||||
try {
|
||||
await this.client.end();
|
||||
} catch (error) {
|
||||
console.warn("강제 연결 해제 중 오류 (무시):", error);
|
||||
} finally {
|
||||
this.client = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async disconnect(): Promise<void> {
|
||||
if (this.client) {
|
||||
await this.client.end();
|
||||
this.client = null;
|
||||
try {
|
||||
const endPromise = this.client.end();
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error("연결 해제 타임아웃")), 3000);
|
||||
});
|
||||
|
||||
await Promise.race([endPromise, timeoutPromise]);
|
||||
console.log(`✅ PostgreSQL 연결 해제 성공`);
|
||||
} catch (error) {
|
||||
console.warn("연결 해제 중 오류:", error);
|
||||
} finally {
|
||||
this.client = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +88,9 @@ export class PostgreSQLConnector implements DatabaseConnector {
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
await this.connect();
|
||||
const result = await this.client!.query("SELECT version(), pg_database_size(current_database()) as size");
|
||||
const result = await this.client!.query(
|
||||
"SELECT version(), pg_database_size(current_database()) as size"
|
||||
);
|
||||
const responseTime = Date.now() - startTime;
|
||||
await this.disconnect();
|
||||
return {
|
||||
@@ -58,7 +99,9 @@ export class PostgreSQLConnector implements DatabaseConnector {
|
||||
details: {
|
||||
response_time: responseTime,
|
||||
server_version: result.rows[0]?.version || "알 수 없음",
|
||||
database_size: this.formatBytes(parseInt(result.rows[0]?.size || "0")),
|
||||
database_size: this.formatBytes(
|
||||
parseInt(result.rows[0]?.size || "0")
|
||||
),
|
||||
},
|
||||
};
|
||||
} catch (error: any) {
|
||||
@@ -91,9 +134,28 @@ export class PostgreSQLConnector implements DatabaseConnector {
|
||||
}
|
||||
|
||||
async getTables(): Promise<TableInfo[]> {
|
||||
let tempClient: Client | null = null;
|
||||
try {
|
||||
await this.connect();
|
||||
const result = await this.client!.query(`
|
||||
console.log(
|
||||
`🔍 PostgreSQL 테이블 목록 조회 시작: ${this.config.host}:${this.config.port}`
|
||||
);
|
||||
|
||||
// 매번 새로운 연결 생성
|
||||
const clientConfig: any = {
|
||||
host: this.config.host,
|
||||
port: this.config.port,
|
||||
database: this.config.database,
|
||||
user: this.config.user,
|
||||
password: this.config.password,
|
||||
connectionTimeoutMillis: 10000,
|
||||
query_timeout: 15000,
|
||||
application_name: "PLM-ERP-Tables",
|
||||
};
|
||||
|
||||
tempClient = new Client(clientConfig);
|
||||
await tempClient.connect();
|
||||
|
||||
const result = await tempClient.query(`
|
||||
SELECT
|
||||
t.table_name,
|
||||
obj_description(quote_ident(t.table_name)::regclass::oid, 'pg_class') as table_description
|
||||
@@ -102,36 +164,81 @@ export class PostgreSQLConnector implements DatabaseConnector {
|
||||
AND t.table_type = 'BASE TABLE'
|
||||
ORDER BY t.table_name;
|
||||
`);
|
||||
await this.disconnect();
|
||||
|
||||
console.log(`✅ 테이블 목록 조회 성공: ${result.rows.length}개`);
|
||||
return result.rows.map((row) => ({
|
||||
table_name: row.table_name,
|
||||
description: row.table_description,
|
||||
columns: [], // Columns will be fetched by getColumns
|
||||
}));
|
||||
} catch (error: any) {
|
||||
await this.disconnect();
|
||||
console.error(`❌ 테이블 목록 조회 실패:`, error.message);
|
||||
throw new Error(`PostgreSQL 테이블 목록 조회 실패: ${error.message}`);
|
||||
} finally {
|
||||
if (tempClient) {
|
||||
try {
|
||||
await tempClient.end();
|
||||
} catch (endError) {
|
||||
console.warn("테이블 조회 연결 해제 중 오류:", endError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getColumns(tableName: string): Promise<any[]> {
|
||||
let tempClient: Client | null = null;
|
||||
try {
|
||||
await this.connect();
|
||||
const result = await this.client!.query(`
|
||||
console.log(
|
||||
`🔍 PostgreSQL 컬럼 정보 조회 시작: ${this.config.host}:${this.config.port}/${tableName}`
|
||||
);
|
||||
|
||||
// 매번 새로운 연결 생성
|
||||
const clientConfig: any = {
|
||||
host: this.config.host,
|
||||
port: this.config.port,
|
||||
database: this.config.database,
|
||||
user: this.config.user,
|
||||
password: this.config.password,
|
||||
connectionTimeoutMillis: 10000,
|
||||
query_timeout: 15000,
|
||||
application_name: "PLM-ERP-Columns",
|
||||
};
|
||||
|
||||
tempClient = new Client(clientConfig);
|
||||
await tempClient.connect();
|
||||
|
||||
const result = await tempClient.query(
|
||||
`
|
||||
SELECT
|
||||
column_name,
|
||||
data_type,
|
||||
is_nullable,
|
||||
column_default
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public' AND table_name = $1
|
||||
ORDER BY ordinal_position;
|
||||
`, [tableName]);
|
||||
await this.disconnect();
|
||||
column_default,
|
||||
col_description(c.oid, a.attnum) as column_comment
|
||||
FROM information_schema.columns isc
|
||||
LEFT JOIN pg_class c ON c.relname = isc.table_name
|
||||
LEFT JOIN pg_attribute a ON a.attrelid = c.oid AND a.attname = isc.column_name
|
||||
WHERE isc.table_schema = 'public' AND isc.table_name = $1
|
||||
ORDER BY isc.ordinal_position;
|
||||
`,
|
||||
[tableName]
|
||||
);
|
||||
|
||||
console.log(
|
||||
`✅ 컬럼 정보 조회 성공: ${tableName} - ${result.rows.length}개`
|
||||
);
|
||||
return result.rows;
|
||||
} catch (error: any) {
|
||||
await this.disconnect();
|
||||
console.error(`❌ 컬럼 정보 조회 실패: ${tableName} -`, error.message);
|
||||
throw new Error(`PostgreSQL 컬럼 정보 조회 실패: ${error.message}`);
|
||||
} finally {
|
||||
if (tempClient) {
|
||||
try {
|
||||
await tempClient.end();
|
||||
} catch (endError) {
|
||||
console.warn("컬럼 조회 연결 해제 중 오류:", endError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,4 +249,4 @@ export class PostgreSQLConnector implements DatabaseConnector {
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user