Skip to content

fix(queue): lift quota blocks whose blocked_until has passed (INV-04) - #130

Closed
Cuarroc wants to merge 2 commits into
mainfrom
claude/inv-04-queue-routing
Closed

Cuarroc wants to merge 2 commits into
mainfrom
claude/inv-04-queue-routing

Conversation

@Cuarroc

@Cuarroc Cuarroc commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Ein Anbieter-Block mit bekanntem Ablaufzeitpunkt blieb in der Warteschlange für immer bestehen, weil ihn nur Ausgabe eines laufenden Workers desselben Profils löschte – und ein blockiertes Profil startet keinen Worker. Jetzt hebt der Dispatcher abgelaufene Blöcke vor jedem Durchgang auf. Dazu liefert dieser PR eine Bestandsaufnahme des Bereichs Warteschlange/Quota (unten) als Grundlage für neue Pakete.

Report

  • Was: QuotaTracker::release_expired(now) (quota.rs) setzt Zeilen mit state=blocked und blocked_until <= now auf ok (persistiert über den Sink); dispatch_project (queue.rs) ruft es vor der Kandidatenschleife. Offene Blöcke (blocked_until = None) bleiben unberührt.
  • Red-first: Commit 2f487d1 (Test-First) – an_elapsed_block_no_longer_holds_its_task an der Merge-Base rot (cargo test --bin projecta an_elapsed_block → FAILED, „the elapsed block is lifted and the task starts"). Fix 1db182e (Regression-For: 2f487d1).
  • Beleg: bash scripts/ci/gates.sh lane prepush mit dem Fix im Baum → Exit 0 (1657 Tests grün, 7 übersprungen, clippy/fmt/lint grün).
  • NICHT ABGEDECKT: #[cfg(windows)]-Tests und Windows-Arme von clippy (Windows-Bahn läuft in der Merge-Queue); der echte Anbieter-Fluss (Statuszeile → Block → Ablauf) ist nicht gegen einen laufenden Agenten gemessen.
  • Review: ausstehend (Stufe B – Rust-Code, Quota/Dispatch ohne Naht). Hinweis: Nebenläufigkeit im Dispatcher berührt, ggf. Stufe A laut Koordinator.

Bestandsaufnahme

Nur Lesen von queue.rs, quota.rs, preflight.rs, budget.rs (Teile), status.rs-Quota-Pfad; routing.rs/workers.rs nicht angefasst (PR #115). Nicht alle Befunde wurden gegen einen Lauf bewiesen.

  1. hoch – status.rs:1474: Anbieter-Blöcke aus der Ausgabe-Heuristik werden immer mit blocked_until=None gespeichert und nur durch Aktivität eines Workers dieses Profils gelöscht (status.rs:1476); ein blockiertes Profil mit leerer Warteschlange startet keinen Worker, der Block überlebt zudem den Neustart (main.rs:3281 hydrate). Dieser PR löst nur den Fall mit Zeitstempel. Vorschlag: Paket „Quota-Probe": Zeitlimit (z. B. Block ohne Zeit läuft nach N Minuten ab bzw. wird einmal pro Sweep probeweise freigegeben) plus Anzeige in der UI/pa quota clear.
  2. mittel – queue.rs:~517 (Dispatcher-Thread, loop { block_on(dispatch_once) }): Panik in einem Launcher beendet den Thread dauerhaft; die Warteschlange steht bis zum App-Neustart, ohne Log. Vorschlag: catch_unwind/Panik-Log pro Sweep.
  3. mittel – queue.rs:~330 (launcher.launch(..).await): kein Zeitlimit; hängt ein Spawn, bleibt der Eintrag dispatching und der ganze Dispatcher blockiert (alle Projekte). Geklärte Claims gibt es nur beim Start (Reattach in main.rs), nicht zur Laufzeit. Vorschlag: tokio::time::timeout + Release des Claims.
  4. mittel – queue.rs:dispatch_once: höchstens ein Eintrag pro Projekt pro 30-s-Sweep (POLL_INTERVAL); zehn bereite Tasks brauchen bis zu 5 Minuten. Vorschlag: nach erfolgreichem Dispatch sofort weiter, bis Kapazität/Liste leer, oder Wake-Signal bei enqueue/Worker-Ende.
  5. niedrig – queue.rs:dispatch_project (Limit): negatives max_workers (usize::try_from schlägt fehl) fällt auf den Standard 4 statt zu pausieren; set_project_max_workers (main.rs:914, Naht) prüft den Wert nicht. Vorschlag: Validierung an der Naht oder <0 = 0 behandeln.
  6. niedrig – queue.rs:gather_facts: agents.json, das einmal nicht lesbar/leer ist, macht Profile „unbekannt" und mark_queue_failed scheitert alle bereiten Tasks dauerhaft (permanenter Blocker). Vorschlag: prüfen, was load_profiles bei Parse-Fehler liefert; bei Fehler Sweep überspringen statt Tasks zu verwerfen (nicht bewiesen).
  7. niedrig – queue.rs:~232 Preflight-Cache-Fingerprint enthält blocked_until, aber nicht die Uhrzeit; TTL 30 s = Sweep-Takt, d. h. praktisch kein Cache-Nutzen (Verbesserung/Vereinfachung, kein Fehler).
  8. Idee (PLAN-Ziel Stabilität) – Testlücke: kein Test für Dispatcher-Panik, Launcher-Hänger und gleichzeitige Sweeps zweier Dispatcher (mark_queue_dispatched-Slot-Race ist getestet, der Rest nicht).

🤖 Generated with Claude Code

Cuarroc and others added 2 commits October 3, 2026 02:12
Test-First: an_elapsed_block_no_longer_holds_its_task
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Regression-For: 2f487d1
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@Cuarroc
Cuarroc marked this pull request as ready for review October 3, 2026 01:04

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1db182e9ff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src-tauri/src/queue.rs
let now = now_unix_secs();
// A block that names its own end must not outlive it: a blocked profile
// starts no worker, so no output would ever clear it.
quota.release_expired(now);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Move quota expiry ahead of capacity returns

In the inspected dispatch_project path, this cleanup runs only after the max_workers == 0 and running >= limit returns. If every project is paused or full—or there are no projects—an elapsed global quota row is therefore never cleared by the dispatcher, leaving get_quota_state, provider views, and the persisted row reporting a profile as blocked past blocked_until. Run the global expiry cleanup once at the start of dispatch_once, before per-project capacity checks.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-03T01:10:02.586958Z 1db182e Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Cuarroc

Cuarroc commented Oct 3, 2026

Copy link
Copy Markdown
Owner Author

Ersetzt durch #183 (gemergt 03.10.). Branch bleibt erhalten.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant