Skip to content

Commit c3d3cdc

Browse files
fix(task-management): delete expired dedup lock before insert to avoid phantom 409
The unique constraint on idempotency_keys(key, org, endpoint) has no expires_at clause, so an expired-but-not-yet-cleaned-up row blocks a fresh INSERT with the same deterministic key. Added a targeted DELETE ... WHERE expires_at < NOW() immediately before the dedup lock INSERT so stale rows never cause a spurious IN_FLIGHT 409. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 9d7cdbd commit c3d3cdc

1 file changed

Lines changed: 14 additions & 1 deletion

File tree

src/controllers/task-management.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,13 +716,26 @@ function TaskManagementController(context) {
716716
.update(`${organizationId}:${[...suggestionIds].sort().join(',')}`)
717717
.digest('hex'); // 64 chars — well within the 128-char column limit
718718

719+
const dedupEndpoint = `dedup:POST /task-management/${provider}/tickets`;
719720
const dedupExpiresAt = new Date(Date.now() + 5 * 60 * 1000).toISOString();
721+
722+
// Remove any expired row with this key so the unique constraint
723+
// does not block a fresh insert (expired rows are not auto-deleted).
724+
await postgrestClient
725+
.from('idempotency_keys')
726+
.delete()
727+
.eq('key', dedupKey)
728+
.eq('organization_id', organizationId)
729+
.eq('endpoint', dedupEndpoint)
730+
.lt('expires_at', new Date().toISOString())
731+
.catch((err) => log.warn({ err }, 'Failed to delete expired dedup lock — proceeding'));
732+
720733
const { data: dedupEntry, error: dedupInsertError } = await postgrestClient
721734
.from('idempotency_keys')
722735
.insert({
723736
key: dedupKey,
724737
organization_id: organizationId,
725-
endpoint: `dedup:POST /task-management/${provider}/tickets`,
738+
endpoint: dedupEndpoint,
726739
status: 'processing',
727740
expires_at: dedupExpiresAt,
728741
})

0 commit comments

Comments
 (0)