summaryrefslogtreecommitdiff
path: root/lib/approval/approval-workflow.ts
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-11-05 19:28:49 +0900
committerjoonhoekim <26rote@gmail.com>2025-11-05 19:28:49 +0900
commite890fbae0c9c273b825ac808aa516de1f87fb218 (patch)
treec2b7bdacd22043a8b4781e9b4c6ea682468abd0f /lib/approval/approval-workflow.ts
parent35e373fe29a4145d0692ee35ff9e6b0c887df0eb (diff)
(김준회) 실사의뢰 결재 오류 수정, 결재 캐시 백그라운드 컨텍스트에서 패스로 무효화 처리, pm2 ecosystem 설정 변경 (npm 레이어 로그 문제), git 줄바꿈 문제 2건 커밋으로 처리
Diffstat (limited to 'lib/approval/approval-workflow.ts')
-rw-r--r--lib/approval/approval-workflow.ts92
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);