제어관리 외부커넥션 설정기능
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 커넥션별 컬럼 정보 조회
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user