fix: preserve paired completion errors without leases (#217)
This commit is contained in:
@@ -1446,6 +1446,34 @@ describe('paired execution context', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('paired execution context completion lease cleanup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('propagates completion handler errors when no execution lease was reserved', () => {
|
||||||
|
const transitionError = new Error('transition failed without lease');
|
||||||
|
vi.mocked(db.getPairedTaskById).mockReturnValue(
|
||||||
|
buildPairedTask({
|
||||||
|
status: 'merge_ready',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
vi.mocked(db.updatePairedTaskIfUnchanged).mockImplementationOnce(() => {
|
||||||
|
throw transitionError;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(() =>
|
||||||
|
completePairedExecutionContext({
|
||||||
|
taskId: 'task-1',
|
||||||
|
role: 'owner',
|
||||||
|
status: 'failed',
|
||||||
|
summary: 'push failed',
|
||||||
|
}),
|
||||||
|
).toThrow('transition failed without lease');
|
||||||
|
expect(db.releasePairedTaskExecutionLease).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('paired execution context reviewer failures', () => {
|
describe('paired execution context reviewer failures', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.resetAllMocks();
|
vi.resetAllMocks();
|
||||||
|
|||||||
@@ -619,15 +619,18 @@ export function preparePairedExecutionContext(args: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function completePairedExecutionContext(args: {
|
type CompletePairedExecutionContextArgs = {
|
||||||
taskId: string;
|
taskId: string;
|
||||||
role: PairedRoomRole;
|
role: PairedRoomRole;
|
||||||
status: 'succeeded' | 'failed';
|
status: 'succeeded' | 'failed';
|
||||||
runId?: string;
|
runId?: string;
|
||||||
summary?: string | null;
|
summary?: string | null;
|
||||||
}): void {
|
};
|
||||||
|
|
||||||
|
export function completePairedExecutionContext(
|
||||||
|
args: CompletePairedExecutionContextArgs,
|
||||||
|
): void {
|
||||||
const { taskId, role, status } = args;
|
const { taskId, role, status } = args;
|
||||||
let completionError: unknown;
|
|
||||||
logger.info(
|
logger.info(
|
||||||
{
|
{
|
||||||
taskId,
|
taskId,
|
||||||
@@ -639,6 +642,28 @@ export function completePairedExecutionContext(args: {
|
|||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
completePairedExecutionContextBody(args);
|
||||||
|
} catch (error) {
|
||||||
|
releaseExecutionLeaseAfterCompletion({
|
||||||
|
taskId,
|
||||||
|
role,
|
||||||
|
runId: args.runId,
|
||||||
|
completionError: error,
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseExecutionLeaseAfterCompletion({
|
||||||
|
taskId,
|
||||||
|
role,
|
||||||
|
runId: args.runId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function completePairedExecutionContextBody(
|
||||||
|
args: CompletePairedExecutionContextArgs,
|
||||||
|
): void {
|
||||||
|
const { taskId, role, status } = args;
|
||||||
const task = getPairedTaskById(taskId);
|
const task = getPairedTaskById(taskId);
|
||||||
if (!task) {
|
if (!task) {
|
||||||
return;
|
return;
|
||||||
@@ -711,28 +736,32 @@ export function completePairedExecutionContext(args: {
|
|||||||
if (role === 'arbiter') {
|
if (role === 'arbiter') {
|
||||||
handleArbiterCompletion({ task, taskId, summary: args.summary });
|
handleArbiterCompletion({ task, taskId, summary: args.summary });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
}
|
||||||
completionError = error;
|
|
||||||
throw error;
|
function releaseExecutionLeaseAfterCompletion(args: {
|
||||||
} finally {
|
taskId: string;
|
||||||
|
role: PairedRoomRole;
|
||||||
|
runId?: string;
|
||||||
|
completionError?: unknown;
|
||||||
|
}): void {
|
||||||
if (!args.runId) {
|
if (!args.runId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
releasePairedTaskExecutionLease({ taskId, runId: args.runId });
|
releasePairedTaskExecutionLease({ taskId: args.taskId, runId: args.runId });
|
||||||
} catch (releaseError) {
|
} catch (releaseError) {
|
||||||
logger.error(
|
logger.error(
|
||||||
{
|
{
|
||||||
taskId,
|
taskId: args.taskId,
|
||||||
role,
|
role: args.role,
|
||||||
runId: args.runId,
|
runId: args.runId,
|
||||||
releaseError,
|
releaseError,
|
||||||
},
|
},
|
||||||
'Failed to release paired task execution lease after completion',
|
'Failed to release paired task execution lease after completion',
|
||||||
);
|
);
|
||||||
if (!completionError) {
|
if (!args.completionError) {
|
||||||
throw releaseError;
|
throw releaseError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user