refactor(l4d2-web): drop refresh_global_overlays from scheduler
GLOBAL_OPERATIONS becomes {"install", "refresh_workshop_items"}.
Removes refresh_global_overlays_running from SchedulerState and the
_run_refresh_global_overlays dispatch. Drops dead test cases and pins
GLOBAL_OPERATIONS contents.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9f476e3456
commit
879c54cbda
4 changed files with 28 additions and 82 deletions
|
|
@ -27,7 +27,7 @@ TERMINAL_JOB_STATES = {"succeeded", "failed", "cancelled"}
|
||||||
ACTIVE_JOB_STATES = {"running", "cancelling"}
|
ACTIVE_JOB_STATES = {"running", "cancelling"}
|
||||||
SERVER_OPERATIONS = {"initialize", "start", "stop", "delete"}
|
SERVER_OPERATIONS = {"initialize", "start", "stop", "delete"}
|
||||||
OVERLAY_OPERATIONS = {"build_overlay"}
|
OVERLAY_OPERATIONS = {"build_overlay"}
|
||||||
GLOBAL_OPERATIONS = {"install", "refresh_workshop_items", "refresh_global_overlays"}
|
GLOBAL_OPERATIONS = {"install", "refresh_workshop_items"}
|
||||||
WORKSHOP_REFRESH_DOWNLOAD_WORKERS = 1
|
WORKSHOP_REFRESH_DOWNLOAD_WORKERS = 1
|
||||||
|
|
||||||
_claim_lock = threading.Lock()
|
_claim_lock = threading.Lock()
|
||||||
|
|
@ -40,7 +40,6 @@ _workers_started = False
|
||||||
class SchedulerState:
|
class SchedulerState:
|
||||||
install_running: bool = False
|
install_running: bool = False
|
||||||
refresh_running: bool = False
|
refresh_running: bool = False
|
||||||
refresh_global_overlays_running: bool = False
|
|
||||||
running_servers: set[int] = field(default_factory=set)
|
running_servers: set[int] = field(default_factory=set)
|
||||||
running_overlays: set[int] = field(default_factory=set)
|
running_overlays: set[int] = field(default_factory=set)
|
||||||
blocked_servers_by_overlay: set[int] = field(default_factory=set)
|
blocked_servers_by_overlay: set[int] = field(default_factory=set)
|
||||||
|
|
@ -63,7 +62,6 @@ def can_start(job, state: SchedulerState) -> bool:
|
||||||
return (
|
return (
|
||||||
not state.install_running
|
not state.install_running
|
||||||
and not state.refresh_running
|
and not state.refresh_running
|
||||||
and not state.refresh_global_overlays_running
|
|
||||||
and len(state.running_servers) == 0
|
and len(state.running_servers) == 0
|
||||||
and len(state.running_overlays) == 0
|
and len(state.running_overlays) == 0
|
||||||
)
|
)
|
||||||
|
|
@ -71,26 +69,17 @@ def can_start(job, state: SchedulerState) -> bool:
|
||||||
return (
|
return (
|
||||||
not state.install_running
|
not state.install_running
|
||||||
and not state.refresh_running
|
and not state.refresh_running
|
||||||
and not state.refresh_global_overlays_running
|
|
||||||
and len(state.running_servers) == 0
|
|
||||||
and len(state.running_overlays) == 0
|
|
||||||
)
|
|
||||||
if job.operation == "refresh_global_overlays":
|
|
||||||
return (
|
|
||||||
not state.install_running
|
|
||||||
and not state.refresh_running
|
|
||||||
and not state.refresh_global_overlays_running
|
|
||||||
and len(state.running_servers) == 0
|
and len(state.running_servers) == 0
|
||||||
and len(state.running_overlays) == 0
|
and len(state.running_overlays) == 0
|
||||||
)
|
)
|
||||||
if job.operation == "build_overlay":
|
if job.operation == "build_overlay":
|
||||||
if state.install_running or state.refresh_running or state.refresh_global_overlays_running:
|
if state.install_running or state.refresh_running:
|
||||||
return False
|
return False
|
||||||
if job.overlay_id is None:
|
if job.overlay_id is None:
|
||||||
return False
|
return False
|
||||||
return job.overlay_id not in state.running_overlays
|
return job.overlay_id not in state.running_overlays
|
||||||
# Server operations from here on.
|
# Server operations from here on.
|
||||||
if state.install_running or state.refresh_running or state.refresh_global_overlays_running:
|
if state.install_running or state.refresh_running:
|
||||||
return False
|
return False
|
||||||
if job.server_id is None:
|
if job.server_id is None:
|
||||||
return False
|
return False
|
||||||
|
|
@ -109,8 +98,6 @@ def build_scheduler_state(session: Session) -> SchedulerState:
|
||||||
state.install_running = True
|
state.install_running = True
|
||||||
elif job.operation == "refresh_workshop_items":
|
elif job.operation == "refresh_workshop_items":
|
||||||
state.refresh_running = True
|
state.refresh_running = True
|
||||||
elif job.operation == "refresh_global_overlays":
|
|
||||||
state.refresh_global_overlays_running = True
|
|
||||||
elif job.operation == "build_overlay" and job.overlay_id is not None:
|
elif job.operation == "build_overlay" and job.overlay_id is not None:
|
||||||
state.running_overlays.add(job.overlay_id)
|
state.running_overlays.add(job.overlay_id)
|
||||||
elif job.server_id is not None:
|
elif job.server_id is not None:
|
||||||
|
|
@ -260,15 +247,6 @@ def run_job(job_id: int) -> None:
|
||||||
on_stderr=on_stderr,
|
on_stderr=on_stderr,
|
||||||
should_cancel=should_cancel,
|
should_cancel=should_cancel,
|
||||||
)
|
)
|
||||||
elif operation == "refresh_global_overlays":
|
|
||||||
_run_with_boundaries(
|
|
||||||
"refresh",
|
|
||||||
"global overlays",
|
|
||||||
_run_refresh_global_overlays,
|
|
||||||
on_stdout=on_stdout,
|
|
||||||
on_stderr=on_stderr,
|
|
||||||
should_cancel=should_cancel,
|
|
||||||
)
|
|
||||||
elif operation == "build_overlay":
|
elif operation == "build_overlay":
|
||||||
if overlay_id_for_job is None:
|
if overlay_id_for_job is None:
|
||||||
raise ValueError("build_overlay job has no overlay_id")
|
raise ValueError("build_overlay job has no overlay_id")
|
||||||
|
|
@ -390,21 +368,6 @@ def _run_build_overlay(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _run_refresh_global_overlays(
|
|
||||||
*,
|
|
||||||
on_stdout: Callable[[str], None],
|
|
||||||
on_stderr: Callable[[str], None],
|
|
||||||
should_cancel: Callable[[], bool],
|
|
||||||
) -> list[str]:
|
|
||||||
from l4d2web.services.global_overlay_refresh import refresh_global_overlays
|
|
||||||
|
|
||||||
return refresh_global_overlays(
|
|
||||||
on_stdout=on_stdout,
|
|
||||||
on_stderr=on_stderr,
|
|
||||||
should_cancel=should_cancel,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _run_refresh_workshop_items(
|
def _run_refresh_workshop_items(
|
||||||
*,
|
*,
|
||||||
on_stdout: Callable[[str], None],
|
on_stdout: Callable[[str], None],
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ def test_system_job_logs_persist(tmp_path, monkeypatch):
|
||||||
job = Job(
|
job = Job(
|
||||||
user_id=None,
|
user_id=None,
|
||||||
server_id=None,
|
server_id=None,
|
||||||
operation="refresh_global_overlays",
|
operation="refresh_workshop_items",
|
||||||
state="queued",
|
state="queued",
|
||||||
)
|
)
|
||||||
db.add(job)
|
db.add(job)
|
||||||
|
|
|
||||||
|
|
@ -752,46 +752,29 @@ def test_refresh_job_enqueues_build_overlay_without_locking_its_final_log(
|
||||||
assert "enqueued build_overlay for 1 overlay(s)" in lines
|
assert "enqueued build_overlay for 1 overlay(s)" in lines
|
||||||
|
|
||||||
|
|
||||||
def test_refresh_global_overlays_blocks_install_build_refresh_and_servers() -> None:
|
def test_global_operations_set() -> None:
|
||||||
from l4d2web.services.job_worker import SchedulerState, can_start
|
from l4d2web.services.job_worker import GLOBAL_OPERATIONS
|
||||||
|
|
||||||
state = SchedulerState(refresh_global_overlays_running=True)
|
assert GLOBAL_OPERATIONS == {"install", "refresh_workshop_items"}
|
||||||
assert can_start(DummyJob(operation="install"), state) is False
|
|
||||||
assert can_start(DummyJob(operation="refresh_workshop_items"), state) is False
|
|
||||||
assert can_start(DummyJob(operation="build_overlay", overlay_id=1), state) is False
|
|
||||||
assert can_start(DummyJob(operation="start", server_id=1), state) is False
|
|
||||||
|
|
||||||
|
|
||||||
def test_refresh_global_overlays_waits_for_active_work() -> None:
|
def test_build_overlay_script_type_blocks_per_overlay(overlay_seeded_worker) -> None:
|
||||||
from l4d2web.services.job_worker import SchedulerState, can_start
|
"""Mechanically identical to workshop builds, but pinned for script type."""
|
||||||
|
app, ids = overlay_seeded_worker
|
||||||
|
with session_scope() as s:
|
||||||
|
overlay = s.query(Overlay).filter_by(id=ids.overlay).one()
|
||||||
|
overlay.type = "script"
|
||||||
|
overlay.script = "echo hi"
|
||||||
|
|
||||||
|
add_job(ids.user, "build_overlay", server_id=None, state="running", overlay_id=ids.overlay)
|
||||||
|
|
||||||
assert can_start(DummyJob(operation="refresh_global_overlays"), SchedulerState(install_running=True)) is False
|
|
||||||
assert can_start(DummyJob(operation="refresh_global_overlays"), SchedulerState(refresh_running=True)) is False
|
|
||||||
state = SchedulerState()
|
state = SchedulerState()
|
||||||
state.running_overlays.add(1)
|
state.running_overlays.add(ids.overlay)
|
||||||
assert can_start(DummyJob(operation="refresh_global_overlays"), state) is False
|
assert (
|
||||||
state = SchedulerState()
|
can_start(DummyJob(operation="build_overlay", overlay_id=ids.overlay), state)
|
||||||
state.running_servers.add(1)
|
is False
|
||||||
assert can_start(DummyJob(operation="refresh_global_overlays"), state) is False
|
)
|
||||||
|
assert (
|
||||||
|
can_start(DummyJob(operation="build_overlay", overlay_id=ids.overlay + 1), state)
|
||||||
def test_run_worker_once_dispatches_refresh_global_overlays(seeded_worker, monkeypatch):
|
is True
|
||||||
from l4d2web.services import job_worker
|
)
|
||||||
from l4d2web.models import Job
|
|
||||||
from l4d2web.db import session_scope
|
|
||||||
|
|
||||||
called = []
|
|
||||||
|
|
||||||
def fake_refresh(*, on_stdout, on_stderr, should_cancel):
|
|
||||||
called.append("refresh")
|
|
||||||
on_stdout("global refresh complete")
|
|
||||||
return ["l4d2center-maps"]
|
|
||||||
|
|
||||||
monkeypatch.setattr(job_worker, "_run_refresh_global_overlays", fake_refresh)
|
|
||||||
with session_scope() as db:
|
|
||||||
job = Job(user_id=None, server_id=None, operation="refresh_global_overlays", state="queued")
|
|
||||||
db.add(job)
|
|
||||||
|
|
||||||
app, ids = seeded_worker
|
|
||||||
assert job_worker.run_worker_once() is True
|
|
||||||
assert called == ["refresh"]
|
|
||||||
|
|
|
||||||
|
|
@ -476,13 +476,13 @@ def test_admin_jobs_page_renders_system_job(tmp_path, monkeypatch) -> None:
|
||||||
sess["user_id"] = admin_id
|
sess["user_id"] = admin_id
|
||||||
|
|
||||||
with session_scope() as db:
|
with session_scope() as db:
|
||||||
db.add(Job(user_id=None, server_id=None, operation="refresh_global_overlays", state="queued"))
|
db.add(Job(user_id=None, server_id=None, operation="refresh_workshop_items", state="queued"))
|
||||||
|
|
||||||
response = admin_client.get("/admin/jobs")
|
response = admin_client.get("/admin/jobs")
|
||||||
text = response.get_data(as_text=True)
|
text = response.get_data(as_text=True)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert "refresh_global_overlays" in text
|
assert "refresh_workshop_items" in text
|
||||||
assert "system" in text
|
assert "system" in text
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -503,7 +503,7 @@ def test_non_admin_cannot_view_system_job(tmp_path, monkeypatch) -> None:
|
||||||
sess["user_id"] = user_id
|
sess["user_id"] = user_id
|
||||||
|
|
||||||
with session_scope() as db:
|
with session_scope() as db:
|
||||||
job = Job(user_id=None, server_id=None, operation="refresh_global_overlays", state="queued")
|
job = Job(user_id=None, server_id=None, operation="refresh_workshop_items", state="queued")
|
||||||
db.add(job)
|
db.add(job)
|
||||||
db.flush()
|
db.flush()
|
||||||
job_id = job.id
|
job_id = job.id
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue