fix(queue): rename queued_ids to active_ids, document circular-dep caveat

This commit is contained in:
damocles 2026-06-04 17:35:56 +02:00 committed by mara
commit 5f05caee31
2 changed files with 14 additions and 4 deletions

View file

@ -96,6 +96,11 @@ each entry finishes. When a dep entry transitions to terminal, the loop re-evalu
the queue immediately, so downstream entries are unblocked with no extra wakeup. No
additional `notify_one()` call is needed.
**Circular-dep caveat**: if A depends on B and B depends on A, neither entry ever
becomes runnable — the worker skips both indefinitely with no error. Callers must
ensure acyclic dep graphs. Cycle detection is deferred to a future iteration (when
parallel workers make a stuck queue more visible).
---
## Container view

View file

@ -468,9 +468,10 @@ impl RebuildQueue {
.filter(|e| e.state.is_terminal())
.map(|e| e.id)
.collect();
// All queued ids — used to distinguish "not yet terminal" from
// "evicted (= resolved)".
let queued_ids: std::collections::HashSet<u64> = inner
// Active (non-terminal) ids: Queued + Running. Named `active_ids`
// rather than `queued_ids` because Running entries are included;
// used to distinguish "still in flight" from "evicted (= resolved)".
let active_ids: std::collections::HashSet<u64> = inner
.entries
.iter()
.filter(|e| !e.state.is_terminal())
@ -480,7 +481,11 @@ impl RebuildQueue {
e.state == QueueState::Queued
&& e.depends_on.iter().all(|dep_id| {
// Resolved if terminal in queue OR not in queue at all.
terminal_ids.contains(dep_id) || !queued_ids.contains(dep_id)
// Note: circular deps (A depends on B, B depends on A)
// silently deadlock — neither entry ever becomes runnable.
// Not a problem in v1 (no callers yet), but callers must
// ensure acyclic dep graphs.
terminal_ids.contains(dep_id) || !active_ids.contains(dep_id)
})
})?;
let entry = &mut inner.entries[pos];