From 356929b399ef31a4de82906267df438cf29ea59d Mon Sep 17 00:00:00 2001 From: 0-Zz-ang Date: Thu, 10 Jul 2025 15:56:13 +0900 Subject: 인터페이스 관련 파일 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/integration-log/db-logging.ts | 295 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 lib/integration-log/db-logging.ts (limited to 'lib/integration-log/db-logging.ts') diff --git a/lib/integration-log/db-logging.ts b/lib/integration-log/db-logging.ts new file mode 100644 index 00000000..990b1096 --- /dev/null +++ b/lib/integration-log/db-logging.ts @@ -0,0 +1,295 @@ +"use server"; + +import { logIntegrationExecution } from "./service"; + +/** + * DB 연동 로깅 래퍼 함수 + * + * @description + * 데이터베이스 작업을 자동으로 로깅하는 래퍼 함수입니다. + * 동기화, 삽입, 수정, 삭제 등 다양한 DB 작업의 실행 시간과 결과를 기록합니다. + * + * @param integrationId 인터페이스 ID (추후 매핑 필요) + * @param tableName 테이블명 + * @param operation 작업 유형 (sync, upsert, delete 등) + * @param processor 실제 DB 작업 함수 + * @returns 처리 결과 + * + * @example + * // 기본 DB 동기화 로깅 + * const syncResult = await withDbLogging( + * 1, // 인터페이스 ID + * 'users', + * 'sync', + * async () => { + * // 외부 시스템에서 사용자 데이터 가져오기 + * const externalUsers = await fetchExternalUsers(); + * + * // 로컬 DB에 동기화 + * const result = await syncUsersToLocalDb(externalUsers); + * + * return { + * totalProcessed: result.length, + * updated: result.filter(u => u.action === 'updated').length, + * created: result.filter(u => u.action === 'created').length + * }; + * } + * ); + * + * @example + * // 데이터 삽입/수정 로깅 + * const upsertResult = await withDbLogging( + * 2, + * 'products', + * 'upsert', + * async () => { + * const productData = await getProductDataFromSap(); + * + * // 기존 데이터 확인 후 삽입/수정 + * const existingProduct = await db.products.findFirst({ + * where: { sapId: productData.sapId } + * }); + * + * if (existingProduct) { + * return await db.products.update({ + * where: { id: existingProduct.id }, + * data: productData + * }); + * } else { + * return await db.products.create({ + * data: productData + * }); + * } + * } + * ); + * + * @example + * // 에러 처리와 함께 + * try { + * const deleteResult = await withDbLogging( + * 3, + * 'temp_data', + * 'cleanup', + * async () => { + * // 7일 이전 임시 데이터 삭제 + * const cutoffDate = new Date(); + * cutoffDate.setDate(cutoffDate.getDate() - 7); + * + * const result = await db.tempData.deleteMany({ + * where: { + * createdAt: { lt: cutoffDate } + * } + * }); + * + * return { deletedCount: result.count }; + * } + * ); + * + * console.log(`${deleteResult.deletedCount}개의 임시 데이터가 삭제됨`); + * } catch (error) { + * console.error('DB 정리 작업 실패:', error); + * } + * + * @example + * // 트랜잭션 내에서 사용 + * const transactionResult = await withDbLogging( + * 4, + * 'orders', + * 'bulk_update', + * async () => { + * return await db.$transaction(async (tx) => { + * // 여러 테이블 업데이트 + * const orders = await tx.orders.updateMany({ + * where: { status: 'pending' }, + * data: { status: 'processing' } + * }); + * + * const orderItems = await tx.orderItems.updateMany({ + * where: { order: { status: 'processing' } }, + * data: { processedAt: new Date() } + * }); + * + * return { ordersUpdated: orders.count, itemsUpdated: orderItems.count }; + * }); + * } + * ); + */ +export async function withDbLogging( + integrationId: number, + tableName: string, + operation: string, + processor: () => Promise +): Promise { + const start = Date.now(); + + try { + // 실제 DB 작업 실행 + const result = await processor(); + + const duration = Date.now() - start; + + // 성공 로그 기록 + await logIntegrationExecution({ + integrationId, + status: 'success', + responseTime: duration, + requestMethod: 'DB', + requestUrl: `${operation}:${tableName}`, + correlationId: `db_${tableName}_${Date.now()}`, + }); + + return result; + + } catch (error) { + const duration = Date.now() - start; + + // 실패 로그 기록 + await logIntegrationExecution({ + integrationId, + status: 'failed', + responseTime: duration, + errorMessage: error instanceof Error ? error.message : 'Unknown error', + requestMethod: 'DB', + requestUrl: `${operation}:${tableName}`, + correlationId: `db_${tableName}_${Date.now()}`, + }); + + throw error; + } +} + +/** + * nonsap 동기화 로깅 헬퍼 함수 + * + * @description + * Non-SAP 시스템과의 데이터 동기화를 로깅하는 전용 헬퍼 함수입니다. + * 전체 동기화(full)와 증분 동기화(delta) 모두 지원합니다. + * + * @param tableName 테이블명 + * @param syncType 동기화 유형 (full, delta) + * @param processor 동기화 작업 함수 + * @returns 처리 결과 + * + * @example + * // 전체 동기화 로깅 + * const fullSyncResult = await withNonsapSyncLogging( + * 'vendors', + * 'full', + * async () => { + * // 외부 시스템에서 전체 벤더 데이터 가져오기 + * const allVendors = await fetchAllVendorsFromExternalSystem(); + * + * // 기존 데이터 모두 삭제 후 재생성 + * await db.vendors.deleteMany({}); + * + * // 새 데이터 삽입 + * const created = await db.vendors.createMany({ + * data: allVendors + * }); + * + * return { + * syncType: 'full', + * totalProcessed: allVendors.length, + * created: created.count, + * updated: 0, + * deleted: 0 + * }; + * } + * ); + * + * @example + * // 증분 동기화 로깅 + * const deltaSyncResult = await withNonsapSyncLogging( + * 'purchase_orders', + * 'delta', + * async () => { + * // 마지막 동기화 이후 변경된 데이터만 가져오기 + * const lastSync = await getLastSyncTimestamp('purchase_orders'); + * const changedOrders = await fetchChangedOrdersSince(lastSync); + * + * let created = 0, updated = 0, deleted = 0; + * + * for (const order of changedOrders) { + * if (order.isDeleted) { + * // 삭제된 데이터 처리 + * await db.purchaseOrders.delete({ where: { externalId: order.id } }); + * deleted++; + * } else { + * // 삽입/수정 데이터 처리 + * const result = await db.purchaseOrders.upsert({ + * where: { externalId: order.id }, + * create: order, + * update: order + * }); + * + * if (result.createdAt === result.updatedAt) { + * created++; + * } else { + * updated++; + * } + * } + * } + * + * // 동기화 타임스탬프 업데이트 + * await updateLastSyncTimestamp('purchase_orders', new Date()); + * + * return { + * syncType: 'delta', + * totalProcessed: changedOrders.length, + * created, + * updated, + * deleted + * }; + * } + * ); + * + * @example + * // 에러 복구가 포함된 동기화 + * const resilientSyncResult = await withNonsapSyncLogging( + * 'inventory', + * 'delta', + * async () => { + * let processedCount = 0; + * let errorCount = 0; + * const errors: string[] = []; + * + * const inventoryUpdates = await fetchInventoryUpdates(); + * + * for (const update of inventoryUpdates) { + * try { + * await db.inventory.upsert({ + * where: { productId: update.productId }, + * create: update, + * update: { quantity: update.quantity, updatedAt: new Date() } + * }); + * processedCount++; + * } catch (error) { + * errorCount++; + * errors.push(`Product ${update.productId}: ${error.message}`); + * + * // 개별 에러는 로그에 남기지만 전체 작업은 계속 진행 + * console.warn(`재고 업데이트 실패 - ${update.productId}:`, error); + * } + * } + * + * return { + * totalItems: inventoryUpdates.length, + * processedCount, + * errorCount, + * errors: errors.slice(0, 10) // 최대 10개 에러만 반환 + * }; + * } + * ); + */ +export async function withNonsapSyncLogging( + tableName: string, + syncType: 'full' | 'delta', + processor: () => Promise +): Promise { + return withDbLogging( + 2, // nonsap 동기화 인터페이스 ID (추후 매핑 필요) + tableName, + `nonsap_${syncType}_sync`, + processor + ); +} \ No newline at end of file -- cgit v1.2.3