mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
Revert "fix(queue): dead/cancelled jobs no longer block idempotency re-submission (#2253)"
This reverts commit c0cb6c533b.
This commit is contained in:
@@ -133,27 +133,12 @@ export class MinionQueue {
|
||||
// 1. Idempotency fast path — if a row already exists for this key, return it
|
||||
// without doing any other work. The unique partial index guarantees
|
||||
// no second row can be inserted with the same non-null key.
|
||||
//
|
||||
// Dead/cancelled jobs represent permanently-failed work whose
|
||||
// idempotency slot must be freed so a fresh attempt can be inserted.
|
||||
// We NULL the key (preserving the row for audit) and fall through
|
||||
// to the INSERT path below.
|
||||
if (opts?.idempotency_key) {
|
||||
const existing = await tx.executeRaw<Record<string, unknown>>(
|
||||
`SELECT * FROM minion_jobs WHERE idempotency_key = $1`,
|
||||
[opts.idempotency_key]
|
||||
);
|
||||
if (existing.length > 0) {
|
||||
const existingJob = rowToMinionJob(existing[0]);
|
||||
if (existingJob.status === 'dead' || existingJob.status === 'cancelled') {
|
||||
await tx.executeRaw(
|
||||
`UPDATE minion_jobs SET idempotency_key = NULL WHERE id = $1`,
|
||||
[existingJob.id]
|
||||
);
|
||||
} else {
|
||||
return existingJob;
|
||||
}
|
||||
}
|
||||
if (existing.length > 0) return rowToMinionJob(existing[0]);
|
||||
}
|
||||
|
||||
// 1b. Submission-time backpressure for high-frequency named jobs.
|
||||
|
||||
@@ -1582,73 +1582,6 @@ describe('MinionQueue: Idempotency', () => {
|
||||
expect(j2.id).toBe(j1.id);
|
||||
expect(j2.data).toEqual({ v: 1 }); // first wins
|
||||
});
|
||||
|
||||
test('dead job with idempotency_key allows re-submission', async () => {
|
||||
const j1 = await queue.add('test-synth', { prompt: 'synthesize' }, {
|
||||
idempotency_key: 'dream:synth:test:abc123',
|
||||
max_attempts: 1,
|
||||
});
|
||||
await engine.executeRaw(
|
||||
`UPDATE minion_jobs SET status = 'dead', finished_at = now() WHERE id = $1`,
|
||||
[j1.id]
|
||||
);
|
||||
const j2 = await queue.add('test-synth', { prompt: 'synthesize' }, {
|
||||
idempotency_key: 'dream:synth:test:abc123',
|
||||
max_attempts: 8,
|
||||
});
|
||||
expect(j2.id).not.toBe(j1.id);
|
||||
expect(j2.status).toBe('waiting');
|
||||
const oldRow = await engine.executeRaw<{ idempotency_key: string | null }>(
|
||||
`SELECT idempotency_key FROM minion_jobs WHERE id = $1`,
|
||||
[j1.id]
|
||||
);
|
||||
expect(oldRow[0].idempotency_key).toBeNull();
|
||||
});
|
||||
|
||||
test('cancelled job with idempotency_key allows re-submission', async () => {
|
||||
const j1 = await queue.add('test-synth', {}, {
|
||||
idempotency_key: 'dream:synth:test:cancel',
|
||||
});
|
||||
await engine.executeRaw(
|
||||
`UPDATE minion_jobs SET status = 'cancelled', finished_at = now() WHERE id = $1`,
|
||||
[j1.id]
|
||||
);
|
||||
const j2 = await queue.add('test-synth', {}, {
|
||||
idempotency_key: 'dream:synth:test:cancel',
|
||||
});
|
||||
expect(j2.id).not.toBe(j1.id);
|
||||
expect(j2.status).toBe('waiting');
|
||||
});
|
||||
|
||||
test('completed job with idempotency_key still blocks re-submission', async () => {
|
||||
const j1 = await queue.add('sync', {}, {
|
||||
idempotency_key: 'dream:synth:test:completed',
|
||||
});
|
||||
await engine.executeRaw(
|
||||
`UPDATE minion_jobs SET status = 'completed', finished_at = now() WHERE id = $1`,
|
||||
[j1.id]
|
||||
);
|
||||
const j2 = await queue.add('sync', {}, {
|
||||
idempotency_key: 'dream:synth:test:completed',
|
||||
});
|
||||
expect(j2.id).toBe(j1.id);
|
||||
expect(j2.status).toBe('completed');
|
||||
});
|
||||
|
||||
test('active job with idempotency_key still blocks re-submission', async () => {
|
||||
const j1 = await queue.add('sync', {}, {
|
||||
idempotency_key: 'dream:synth:test:active',
|
||||
});
|
||||
await engine.executeRaw(
|
||||
`UPDATE minion_jobs SET status = 'active' WHERE id = $1`,
|
||||
[j1.id]
|
||||
);
|
||||
const j2 = await queue.add('sync', {}, {
|
||||
idempotency_key: 'dream:synth:test:active',
|
||||
});
|
||||
expect(j2.id).toBe(j1.id);
|
||||
expect(j2.status).toBe('active');
|
||||
});
|
||||
});
|
||||
|
||||
// --- v7 child_done auto-post ---
|
||||
|
||||
Reference in New Issue
Block a user