diff options
| author | joonhoekim <26rote@gmail.com> | 2025-11-05 19:28:49 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-11-05 19:28:49 +0900 |
| commit | e890fbae0c9c273b825ac808aa516de1f87fb218 (patch) | |
| tree | c2b7bdacd22043a8b4781e9b4c6ea682468abd0f /lib/approval/approval-workflow.ts | |
| parent | 35e373fe29a4145d0692ee35ff9e6b0c887df0eb (diff) | |
(김준회) 실사의뢰 결재 오류 수정, 결재 캐시 백그라운드 컨텍스트에서 패스로 무효화 처리, pm2 ecosystem 설정 변경 (npm 레이어 로그 문제), git 줄바꿈 문제 2건 커밋으로 처리
Diffstat (limited to 'lib/approval/approval-workflow.ts')
| -rw-r--r-- | lib/approval/approval-workflow.ts | 92 |
1 files changed, 85 insertions, 7 deletions
diff --git a/lib/approval/approval-workflow.ts b/lib/approval/approval-workflow.ts index 4c7eec09..fc6a0dcf 100644 --- a/lib/approval/approval-workflow.ts +++ b/lib/approval/approval-workflow.ts @@ -180,6 +180,11 @@ export async function withApproval<T>( * - Knox 상신 성공 후 DB 업데이트 실패 위험 제거 */ + // 캐시 무효화 (결재 상신 시) + console.log(`[Approval Workflow] Revalidating cache after approval submission`); + const { revalidateApprovalLogs } = await import('./cache-utils'); + await revalidateApprovalLogs(); + let pendingActionId: number | undefined; try { @@ -253,38 +258,81 @@ export async function withApproval<T>( * @returns 액션 실행 결과 */ export async function executeApprovedAction(apInfId: string) { + // debug-utils import + const { debugLog, debugError, debugSuccess } = await import('@/lib/debug-utils'); + + debugLog('[executeApprovedAction] 시작', { apInfId }); + try { // 핸들러 자동 초기화 (폴링 서비스의 격리 문제 해결) + debugLog('[executeApprovedAction] 핸들러 초기화 중'); await ensureHandlersInitialized(); + debugLog('[executeApprovedAction] 핸들러 초기화 완료'); // 1. apInfId로 pendingAction 조회 + debugLog('[executeApprovedAction] pendingAction 조회 중', { apInfId }); const pendingAction = await db.query.pendingActions.findFirst({ where: eq(pendingActions.apInfId, apInfId), }); if (!pendingAction) { + debugLog('[executeApprovedAction] pendingAction 없음 (결재만 존재)', { apInfId }); console.log(`[Approval Workflow] No pending action found for approval: ${apInfId}`); return null; // 결재만 있고 실행할 액션이 없는 경우 } + debugLog('[executeApprovedAction] pendingAction 조회 완료', { + id: pendingAction.id, + actionType: pendingAction.actionType, + status: pendingAction.status, + createdBy: pendingAction.createdBy, + }); + // 이미 실행되었거나 실패한 액션은 스킵 if (['executed', 'failed'].includes(pendingAction.status)) { + debugLog('[executeApprovedAction] 이미 처리된 액션 스킵', { + apInfId, + status: pendingAction.status, + }); console.log(`[Approval Workflow] Pending action already processed: ${apInfId} (${pendingAction.status})`); return null; } // 2. 등록된 핸들러 조회 + debugLog('[executeApprovedAction] 핸들러 조회 중', { + actionType: pendingAction.actionType, + }); const handler = actionHandlers.get(pendingAction.actionType); if (!handler) { + debugError('[executeApprovedAction] 핸들러를 찾을 수 없음', { + actionType: pendingAction.actionType, + availableHandlers: Array.from(actionHandlers.keys()), + }); console.error('[Approval Workflow] Available handlers:', Array.from(actionHandlers.keys())); throw new Error(`Handler not found for action type: ${pendingAction.actionType}`); } + debugLog('[executeApprovedAction] 핸들러 조회 완료', { + actionType: pendingAction.actionType, + }); // 3. 실제 액션 실행 + debugLog('[executeApprovedAction] 핸들러 실행 시작', { + actionType: pendingAction.actionType, + apInfId, + payloadKeys: Object.keys(pendingAction.actionPayload || {}), + }); console.log(`[Approval Workflow] Executing action: ${pendingAction.actionType} (${apInfId})`); + const result = await handler(pendingAction.actionPayload); + debugSuccess('[executeApprovedAction] 핸들러 실행 완료', { + actionType: pendingAction.actionType, + apInfId, + resultKeys: result ? Object.keys(result) : [], + }); + // 4. 실행 완료 상태 업데이트 + debugLog('[executeApprovedAction] 상태 업데이트 중 (executed)'); await db.update(pendingActions) .set({ status: 'executed', @@ -292,21 +340,46 @@ export async function executeApprovedAction(apInfId: string) { executionResult: result, }) .where(eq(pendingActions.apInfId, apInfId)); + debugLog('[executeApprovedAction] 상태 업데이트 완료 (executed)'); + // 5. 캐시 무효화 (백그라운드에서도 동작) + debugLog('[executeApprovedAction] 캐시 무효화 중'); + const { revalidateApprovalLogs } = await import('./cache-utils'); + await revalidateApprovalLogs(); + debugLog('[executeApprovedAction] 캐시 무효화 완료'); + + debugSuccess('[executeApprovedAction] 전체 프로세스 완료', { + actionType: pendingAction.actionType, + apInfId, + }); console.log(`[Approval Workflow] ✅ Successfully executed: ${pendingAction.actionType} (${apInfId})`); return result; } catch (error) { + debugError('[executeApprovedAction] 실행 중 에러 발생', { + apInfId, + error: error instanceof Error ? error.message : String(error), + stack: error instanceof Error ? error.stack : undefined, + }); console.error(`[Approval Workflow] ❌ Failed to execute action for ${apInfId}:`, error); // 실패 상태 업데이트 - await db.update(pendingActions) - .set({ - status: 'failed', - errorMessage: error instanceof Error ? error.message : String(error), - executedAt: new Date(), - }) - .where(eq(pendingActions.apInfId, apInfId)); + try { + debugLog('[executeApprovedAction] 상태 업데이트 중 (failed)'); + await db.update(pendingActions) + .set({ + status: 'failed', + errorMessage: error instanceof Error ? error.message : String(error), + executedAt: new Date(), + }) + .where(eq(pendingActions.apInfId, apInfId)); + debugLog('[executeApprovedAction] 상태 업데이트 완료 (failed)'); + } catch (updateError) { + debugError('[executeApprovedAction] 상태 업데이트 실패', { + apInfId, + updateError: updateError instanceof Error ? updateError.message : String(updateError), + }); + } throw error; } @@ -337,6 +410,11 @@ export async function handleRejectedAction(apInfId: string, reason?: string) { }) .where(eq(pendingActions.apInfId, apInfId)); + // 캐시 무효화 (백그라운드에서도 동작) + console.log(`[Approval Workflow] Revalidating cache for rejected action: ${apInfId}`); + const { revalidateApprovalLogs } = await import('./cache-utils'); + await revalidateApprovalLogs(); + // TODO: 요청자에게 알림 발송 등 추가 처리 } catch (error) { console.error(`[Approval Workflow] Failed to handle rejected action for approval ${apInfId}:`, error); |
