Make resource-scoped task deduplication atomic #15
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Resource-scoped task deduplication is currently implemented as a read-then-insert flow, which is race-prone under concurrent requests.
Why this is a problem:
user_id + task_type + resource_keycan both observe no in-flight task and enqueue duplicate jobs.Observed in:
lib/server/tasks.tsfindOrEnqueueTask()lib/server/repos/tasks.tscreateTaskRunRecord()inserts unconditionallylib/server/db/schema.tstask_runhas an index onuser_id, task_type, resource_key, status, created_atSuggested direction:
Acceptance criteria:
{"body":"Fixed via:
task_active_resource_uidxon (user_id, task_type, resource_key) WHERE status IN ('queued', 'running')createTaskRunRecordAtomic()with try-catch for constraint violationsfindOrEnqueueTask()to use insert-first patternThe race condition is now prevented at the database level. 10-way concurrent tests verify only one task is created per resource.
Files changed:
drizzle/0013_task_active_resource_unique.sql(new migration)lib/server/db/schema.ts(documentation)lib/server/repos/tasks.ts(atomic create function)lib/server/tasks.ts(updated findOrEnqueueTask)lib/server/repos/tasks.test.ts(race condition tests)lib/server/db/sqlite-schema-compat.ts(index for existing DBs)"}Fixed via:
task_active_resource_uidxon (user_id, task_type, resource_key) WHERE status IN ('queued', 'running')createTaskRunRecordAtomic()with try-catch for constraint violationsfindOrEnqueueTask()to use insert-first patternThe race condition is now prevented at the database level. 10-way concurrent tests verify only one task is created per resource.
Files changed:
drizzle/0013_task_active_resource_unique.sql(new migration)lib/server/db/schema.ts(documentation)lib/server/repos/tasks.ts(atomic create function)lib/server/tasks.ts(updated findOrEnqueueTask)lib/server/repos/tasks.test.ts(race condition tests)lib/server/db/sqlite-schema-compat.ts(index for existing DBs)