Problem
PriorityJobQueue.is_done in cli/localci/core/queue.py (lines 351-352) reads len(self._jobs) and len(self._completed_keys) without acquiring self._lock, while adjacent accessors such as is_empty (lines 346-348) and get_all_jobs() (lines 396-398) do take it. ParallelExecutionManager._dispatch_loop() polls self.queue.is_done every dispatch_interval seconds (orchestrator.py line 301), concurrently with enqueue() and mark_complete() mutations under the lock, creating a torn-read race in which completion can be observed incorrectly. Eval Test 13 (Thread Safety) identifies this gap.
Acceptance Criteria
Implementation Notes
Wrap lines 351-352 in with self._lock:, following the is_empty pattern at lines 346-348. The sibling unlocked counters completed_count and running_count (lines 364-369) may need the same treatment, but scope this issue to is_done only and file a follow-up if warranted.
References
- Eval finding: Test 13, Thread Safety
- Related files:
cli/localci/core/queue.py, cli/localci/core/orchestrator.py, cli/tests/test_queue.py
Problem
PriorityJobQueue.is_doneincli/localci/core/queue.py(lines 351-352) readslen(self._jobs)andlen(self._completed_keys)without acquiringself._lock, while adjacent accessors such asis_empty(lines 346-348) andget_all_jobs()(lines 396-398) do take it.ParallelExecutionManager._dispatch_loop()pollsself.queue.is_doneeverydispatch_intervalseconds (orchestrator.pyline 301), concurrently withenqueue()andmark_complete()mutations under the lock, creating a torn-read race in which completion can be observed incorrectly. Eval Test 13 (Thread Safety) identifies this gap.Acceptance Criteria
PriorityJobQueue.is_doneacquiresself._lockfor the full read of_jobsand_completed_keyscli/tests/test_queue.pyaround lines 340-347, does not observeis_doneflipping incorrectly during concurrent enqueue and completeParallelExecutionManagerdispatch behaviour is unchanged for valid sequential runsImplementation Notes
Wrap lines 351-352 in
with self._lock:, following theis_emptypattern at lines 346-348. The sibling unlocked counterscompleted_countandrunning_count(lines 364-369) may need the same treatment, but scope this issue tois_doneonly and file a follow-up if warranted.References
cli/localci/core/queue.py,cli/localci/core/orchestrator.py,cli/tests/test_queue.py