Description
The is_host_available check and the subsequent create_schedule call are not atomic. Between the availability check and the actual schedule insertion, another concurrent request can claim the same host for the same time range, resulting in double-allocation of bare metal hosts.
Reproduction
Thread A: is_host_available("host1", start, end) -> True
Thread B: is_host_available("host1", start, end) -> True
Thread A: create_schedule(host1, start, end) -> OK
Thread B: create_schedule(host1, start, end) -> OK <-- Double booking!
Affected Code
src/quads/server/dao/schedule.py:300-320 (is_host_available)
src/quads/server/blueprints/schedules.py:294-303 (create_schedule)
Root Cause
No row-level locking (SELECT FOR UPDATE) or database-level unique constraint prevents concurrent allocation of the same host for overlapping time ranges.
Recommended Fix
- Use database-level locking (
SELECT ... FOR UPDATE) around the availability check and schedule insertion within a single transaction.
- Alternatively, add a database exclusion constraint on the
schedules table to prevent overlapping time ranges per host.
Description
The
is_host_availablecheck and the subsequentcreate_schedulecall are not atomic. Between the availability check and the actual schedule insertion, another concurrent request can claim the same host for the same time range, resulting in double-allocation of bare metal hosts.Reproduction
Affected Code
src/quads/server/dao/schedule.py:300-320(is_host_available)src/quads/server/blueprints/schedules.py:294-303(create_schedule)Root Cause
No row-level locking (
SELECT FOR UPDATE) or database-level unique constraint prevents concurrent allocation of the same host for overlapping time ranges.Recommended Fix
SELECT ... FOR UPDATE) around the availability check and schedule insertion within a single transaction.schedulestable to prevent overlapping time ranges per host.