import { createLogger } from '@sim/logger' import { describeError, toError } from '@sim/utils/errors' import { isRetryableInfrastructureError } from '@/lib/core/errors/retryable-infrastructure' import type { LoggingSession } from '@/lib/logs/execution/logging-session' import { PauseResumeManager } from '@/lib/workflows/executor/human-in-the-loop-manager' import type { ExecutionResult } from '@/executor/types' const logger = createLogger('PausePersistence') interface HandlePostExecutionPauseStateArgs { result: ExecutionResult workflowId: string executionId: string loggingSession: LoggingSession } /** * Handles pause persistence and resume queue processing after `executeWorkflowCore` returns. * * Every caller of `executeWorkflowCore` must call this after execution completes * to ensure HITL pause state is persisted to the database and queued resumes are drained. * * - If execution is paused with a valid snapshot: persists to `paused_executions` table * - If execution is paused without a snapshot: marks execution as failed * - If execution is not paused: processes any queued resume entries */ export async function handlePostExecutionPauseState({ result, workflowId, executionId, loggingSession, }: HandlePostExecutionPauseStateArgs): Promise { if (result.status === 'paused') { if (!result.snapshotSeed) { logger.error('Missing snapshot seed for paused execution', { executionId }) await loggingSession.markAsFailed('Missing snapshot seed for paused execution') } else { try { await PauseResumeManager.persistPauseResult({ workflowId, executionId, pausePoints: result.pausePoints || [], snapshotSeed: result.snapshotSeed, executorUserId: result.metadata?.userId, }) } catch (pauseError) { logger.error('Failed to persist pause result', { executionId, error: toError(pauseError).message, cause: describeError(pauseError), retryable: isRetryableInfrastructureError(pauseError), }) await loggingSession.markAsFailed( `Failed to persist pause state: ${toError(pauseError).message}` ) } } } else { try { await PauseResumeManager.processQueuedResumes(executionId, workflowId) } catch (resumeError) { logger.error('Failed to process queued resumes', { executionId, error: toError(resumeError).message, cause: describeError(resumeError), retryable: isRetryableInfrastructureError(resumeError), }) } } }