Skip to content

Take the lock in PriorityJobQueue.is_done #100

Description

@bradjin8

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

  • PriorityJobQueue.is_done acquires self._lock for the full read of _jobs and _completed_keys
  • A concurrent stress test, extending the threading tests in cli/tests/test_queue.py around lines 340-347, does not observe is_done flipping incorrectly during concurrent enqueue and complete
  • ParallelExecutionManager dispatch behaviour is unchanged for valid sequential runs
  • Tests pass in CI
  • PR approved by at least 1 reviewer

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions