(payload: ResumeExecutionPayload)
| 22 | } |
| 23 | |
| 24 | export async function executeResumeJob(payload: ResumeExecutionPayload) { |
| 25 | const { resumeExecutionId, pausedExecutionId, contextId, workflowId, parentExecutionId } = payload |
| 26 | |
| 27 | logger.info('Starting background resume execution', { |
| 28 | resumeExecutionId, |
| 29 | pausedExecutionId, |
| 30 | contextId, |
| 31 | workflowId, |
| 32 | parentExecutionId, |
| 33 | }) |
| 34 | |
| 35 | try { |
| 36 | const pausedExecution = await PauseResumeManager.getPausedExecutionById(pausedExecutionId) |
| 37 | if (!pausedExecution) { |
| 38 | throw new Error(`Paused execution not found: ${pausedExecutionId}`) |
| 39 | } |
| 40 | |
| 41 | // If this paused execution belongs to a table cell, rehydrate the cell |
| 42 | // context so post-resume block outputs land on the same row + group as |
| 43 | // the original cell task. Without this, blocks that run after the human |
| 44 | // approves write nothing back to the table — the row silently truncates |
| 45 | // at the pause boundary. |
| 46 | const { findCellContextByExecutionId } = await import('@/lib/table/workflow-columns') |
| 47 | const cellContext = await findCellContextByExecutionId(parentExecutionId) |
| 48 | |
| 49 | // A paused/awaiting table cell that was cancelled by "Stop all" must not |
| 50 | // resume — the cancel write is authoritative (matches the cell-write guard |
| 51 | // philosophy). Aborting here also stops the wasted compute the guard alone |
| 52 | // can't prevent. Read the cell's current exec and bail if cancelled. |
| 53 | if (cellContext) { |
| 54 | const { getRowById } = await import('@/lib/table/rows/service') |
| 55 | const cellRow = await getRowById( |
| 56 | cellContext.tableId, |
| 57 | cellContext.rowId, |
| 58 | cellContext.workspaceId |
| 59 | ) |
| 60 | if (isExecCancelled(cellRow?.executions?.[cellContext.groupId])) { |
| 61 | logger.info('Skipping resume — table cell cancelled', { |
| 62 | tableId: cellContext.tableId, |
| 63 | rowId: cellContext.rowId, |
| 64 | groupId: cellContext.groupId, |
| 65 | parentExecutionId, |
| 66 | }) |
| 67 | return { |
| 68 | success: false, |
| 69 | workflowId, |
| 70 | executionId: resumeExecutionId, |
| 71 | parentExecutionId, |
| 72 | status: 'cancelled' as const, |
| 73 | output: undefined, |
| 74 | executedAt: new Date().toISOString(), |
| 75 | } |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | const writers = cellContext |
| 80 | ? await buildResumeCellWriters(cellContext, parentExecutionId) |
| 81 | : null |
no test coverage detected