제어관리 외부커넥션 설정기능

This commit is contained in:
kjs
2025-09-26 01:28:51 +09:00
parent 1a59c0cf04
commit 2a4e379dc4
43 changed files with 7129 additions and 316 deletions

View File

@@ -6,12 +6,12 @@
import { ExternalDbConnectionService } from "./externalDbConnectionService";
import { TableManagementService } from "./tableManagementService";
import { ExternalDbConnection } from "../types/externalDbTypes";
import { ExternalDbConnection, ApiResponse } from "../types/externalDbTypes";
import { ColumnTypeInfo, TableInfo } from "../types/tableManagement";
import { PrismaClient } from "@prisma/client";
import { logger } from "../utils/logger";
const prisma = new PrismaClient();
// 🔧 Prisma 클라이언트 중복 생성 방지 - 기존 인스턴스 재사용
import prisma = require("../config/database");
export interface ValidationResult {
isValid: boolean;
@@ -426,6 +426,171 @@ export class MultiConnectionQueryService {
}
}
/**
* 배치 테이블 정보 조회 (컬럼 수 포함)
*/
async getBatchTablesWithColumns(
connectionId: number
): Promise<
{ tableName: string; displayName?: string; columnCount: number }[]
> {
try {
logger.info(`배치 테이블 정보 조회 시작: connectionId=${connectionId}`);
// connectionId가 0이면 메인 DB
if (connectionId === 0) {
console.log("🔍 메인 DB 배치 테이블 정보 조회");
// 메인 DB의 모든 테이블과 각 테이블의 컬럼 수 조회
const tables = await this.tableManagementService.getTableList();
const result = await Promise.all(
tables.map(async (table) => {
try {
const columnsResult =
await this.tableManagementService.getColumnList(
table.tableName,
1,
1000
);
return {
tableName: table.tableName,
displayName: table.displayName,
columnCount: columnsResult.columns.length,
};
} catch (error) {
logger.warn(
`메인 DB 테이블 ${table.tableName} 컬럼 수 조회 실패:`,
error
);
return {
tableName: table.tableName,
displayName: table.displayName,
columnCount: 0,
};
}
})
);
logger.info(`✅ 메인 DB 배치 조회 완료: ${result.length}개 테이블`);
return result;
}
// 외부 DB 연결 정보 가져오기
const connectionResult =
await ExternalDbConnectionService.getConnectionById(connectionId);
if (!connectionResult.success || !connectionResult.data) {
throw new Error(`커넥션을 찾을 수 없습니다: ${connectionId}`);
}
const connection = connectionResult.data;
console.log(
`🔍 외부 DB 배치 테이블 정보 조회: connectionId=${connectionId}`
);
// 외부 DB의 테이블 목록 먼저 조회
const tablesResult =
await ExternalDbConnectionService.getTables(connectionId);
if (!tablesResult.success || !tablesResult.data) {
throw new Error("외부 DB 테이블 목록 조회 실패");
}
const tableNames = tablesResult.data;
// 🔧 각 테이블의 컬럼 수를 순차적으로 조회 (타임아웃 방지)
const result = [];
logger.info(
`📊 외부 DB 테이블 컬럼 조회 시작: ${tableNames.length}개 테이블`
);
for (let i = 0; i < tableNames.length; i++) {
const tableInfo = tableNames[i];
const tableName = tableInfo.table_name;
try {
logger.info(
`📋 테이블 ${i + 1}/${tableNames.length}: ${tableName} 컬럼 조회 중...`
);
// 🔧 타임아웃과 재시도 로직 추가
let columnsResult: ApiResponse<any[]> | undefined;
let retryCount = 0;
const maxRetries = 2;
while (retryCount <= maxRetries) {
try {
columnsResult = (await Promise.race([
ExternalDbConnectionService.getTableColumns(
connectionId,
tableName
),
new Promise<ApiResponse<any[]>>((_, reject) =>
setTimeout(
() => reject(new Error("컬럼 조회 타임아웃 (15초)")),
15000
)
),
])) as ApiResponse<any[]>;
break; // 성공하면 루프 종료
} catch (attemptError) {
retryCount++;
if (retryCount > maxRetries) {
throw attemptError; // 최대 재시도 후 에러 throw
}
logger.warn(
`⚠️ 테이블 ${tableName} 컬럼 조회 실패 (${retryCount}/${maxRetries}), 재시도 중...`
);
await new Promise((resolve) => setTimeout(resolve, 1000)); // 1초 대기 후 재시도
}
}
const columnCount =
columnsResult &&
columnsResult.success &&
Array.isArray(columnsResult.data)
? columnsResult.data.length
: 0;
result.push({
tableName,
displayName: tableName, // 외부 DB는 일반적으로 displayName이 없음
columnCount,
});
logger.info(`✅ 테이블 ${tableName}: ${columnCount}개 컬럼`);
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : String(error);
logger.warn(
`❌ 외부 DB 테이블 ${tableName} 컬럼 수 조회 최종 실패: ${errorMessage}`
);
result.push({
tableName,
displayName: tableName,
columnCount: 0, // 실패한 경우 0으로 설정
});
}
// 🔧 연결 부하 방지를 위한 약간의 지연
if (i < tableNames.length - 1) {
await new Promise((resolve) => setTimeout(resolve, 100)); // 100ms 지연
}
}
logger.info(`✅ 외부 DB 배치 조회 완료: ${result.length}개 테이블`);
return result;
} catch (error) {
logger.error(
`배치 테이블 정보 조회 실패: connectionId=${connectionId}, error=${
error instanceof Error ? error.message : error
}`
);
throw error;
}
}
/**
* 커넥션별 컬럼 정보 조회
*/