Implement persistent queue engine Refs #6

This commit is contained in:
2026-07-30 09:01:25 +02:00
parent 72562eab95
commit a088d840e3
5 changed files with 262 additions and 41 deletions
+37 -3
View File
@@ -106,6 +106,7 @@ def test_queue_jobs_include_groups_and_manual_context(tmp_path, monkeypatch):
assert jobs[0]["group"] == "manual_batch"
assert jobs[0]["relative_path"] == "Release/Season 1/Episode.mkv"
assert jobs[0]["can_run_now"] is True
assert jobs[0]["state"] == "ready"
def test_queue_item_retry_ignore_and_remove_actions(tmp_path, monkeypatch):
@@ -132,8 +133,8 @@ def test_queue_item_run_now_imports_only_selected_item(tmp_path, monkeypatch):
waiting = batch / "Waiting.mkv"
selected.write_bytes(b"selected")
waiting.write_bytes(b"waiting")
selected_row = main.state.upsert_queue_item(source_type="manual", source_id=str(selected), source_path=selected, name=selected.name, state="manual_batch")
main.state.upsert_queue_item(source_type="manual", source_id=str(waiting), source_path=waiting, name=waiting.name, state="manual_batch")
selected_row = main.state.upsert_queue_item(source_type="manual", source_id=str(selected), source_path=selected, name=selected.name, state="ready")
main.state.upsert_queue_item(source_type="manual", source_id=str(waiting), source_path=waiting, name=waiting.name, state="ready")
result = main.queue_item_action(selected_row["id"], main.QueueItemActionRequest(action="run-now"))
@@ -143,7 +144,7 @@ def test_queue_item_run_now_imports_only_selected_item(tmp_path, monkeypatch):
assert waiting.exists()
rows = {row["name"]: row for row in main.state.list_queue_items(active_only=False)}
assert rows["Selected.mkv"]["state"] == "imported"
assert rows["Waiting.mkv"]["state"] == "manual_batch"
assert rows["Waiting.mkv"]["state"] == "ready"
def test_current_job_status_includes_progress(tmp_path, monkeypatch):
@@ -198,6 +199,39 @@ def test_cancel_current_stops_active_copy(tmp_path, monkeypatch):
assert main.state.list_queue_items(active_only=False)[0]["state"] == "skipped"
def test_status_includes_queue_counts(tmp_path, monkeypatch):
main, _download, _movies, _tv = configure_main(tmp_path, monkeypatch)
main.state.upsert_queue_item(source_type="manual", source_id="a", name="A.mkv", state="ready")
main.state.upsert_queue_item(source_type="manual", source_id="b", name="B.mkv", state="failed")
status = main.status()
assert status["queue_total"] == 2
assert status["queue_counts"]["ready"] == 1
assert status["queue_counts"]["failed"] == 1
def test_worker_claimed_failure_retries_item(tmp_path, monkeypatch):
main, download, movies, tv = configure_main(tmp_path, monkeypatch)
batch = download / "Release"
batch.mkdir(parents=True)
source = batch / "A.mkv"
source.write_bytes(b"a")
row = main.state.upsert_queue_item(source_type="manual", source_id=str(source), source_path=source, name=source.name, state="ready")
claimed = main.state.claim_next_queue_item(main.WORKER_ID)
class BrokenImporter:
def import_file(self, *args, **kwargs):
raise RuntimeError("boom")
imported = main._import_queue_item(claimed, BrokenImporter(), from_worker=True)
updated = main.state.get_queue_item(row["id"])
assert imported == 0
assert updated["state"] == "retrying"
assert updated["attempt_count"] == 1
def test_control_update_runs_configured_command(tmp_path, monkeypatch):
main, _download, _movies, _tv = configure_main(tmp_path, monkeypatch)
main.settings.update_command = ["upgrade", "now"]
+34
View File
@@ -11,3 +11,37 @@ def test_delete_queue_items_by_state_can_target_reason(tmp_path):
rows = state.list_queue_items()
assert len(rows) == 1
assert rows[0]["source_id"] == "other"
def test_upsert_preserves_terminal_state_by_default(tmp_path):
state = State(tmp_path / "state.db")
state.upsert_queue_item(source_type="manual", source_id="a", name="A.mkv", state="failed", reason="boom")
updated = state.upsert_queue_item(source_type="manual", source_id="a", name="A.mkv", state="ready", reason="rescanned")
assert updated["state"] == "failed"
assert updated["reason"] == "boom"
def test_claim_next_queue_item_marks_importing(tmp_path):
state = State(tmp_path / "state.db")
state.upsert_queue_item(source_type="manual", source_id="a", name="A.mkv", state="ready")
row = state.claim_next_queue_item("worker-1")
assert row is not None
assert row["state"] == "importing"
assert row["claimed_by"] == "worker-1"
def test_release_stale_claims_requeues_importing_items(tmp_path):
state = State(tmp_path / "state.db")
state.upsert_queue_item(source_type="manual", source_id="a", name="A.mkv", state="ready")
state.claim_next_queue_item("worker-1")
released = state.release_stale_claims("worker-1")
row = state.get_queue_item(1)
assert released == 1
assert row["state"] == "retrying"
assert row["claimed_by"] is None