sched: bind ownership to store composition; stable recovery failure; schema-checked prepare; guarded settle (R4 wave 2)

This commit is contained in:
lda
2026-09-08 18:36:09 +07:00 Verified
parent b9d8eb9d16
commit 3f1d5d158b
16 changed files with 1299 additions and 60 deletions
+9 -9
View File
@@ -83,7 +83,7 @@ def _due(sched: Scheduler, store: FileScheduleStore, intended: datetime) -> None
def test_executing_is_set_before_executor_runs(tmp_path: Path) -> None:
ownership = SchedulerOwnership(tmp_path / "sched", owner="test").acquire()
ownership = SchedulerOwnership(tmp_path, owner="test").acquire()
try:
observed: dict[str, bool] = {}
@@ -128,7 +128,7 @@ def test_failure_before_transition_never_dispatches(tmp_path: Path) -> None:
sched_store = FileScheduleStore(tmp_path / "sched")
run_store = FailMarkOnce(tmp_path / "runs")
ownership = SchedulerOwnership(tmp_path / "sched", owner="test").acquire()
ownership = SchedulerOwnership(tmp_path, owner="test").acquire()
try:
sched = Scheduler(
schedule_store=sched_store,
@@ -160,7 +160,7 @@ def test_failure_before_transition_never_dispatches(tmp_path: Path) -> None:
def test_capacity_shortage_keeps_pending_undispatched(tmp_path: Path) -> None:
calls: list[str] = []
ownership = SchedulerOwnership(tmp_path / "sched", owner="test").acquire()
ownership = SchedulerOwnership(tmp_path, owner="test").acquire()
try:
sched, store, runs = _harness(tmp_path, ownership, capacity=0)
intended = ts(2026, 9, 8, 12, 0)
@@ -185,7 +185,7 @@ def test_capacity_shortage_keeps_pending_undispatched(tmp_path: Path) -> None:
def test_pending_on_terminal_run_clears_without_redispatch(tmp_path: Path) -> None:
calls: list[str] = []
ownership = SchedulerOwnership(tmp_path / "sched", owner="test").acquire()
ownership = SchedulerOwnership(tmp_path, owner="test").acquire()
try:
sched, store, runs = _harness(tmp_path, ownership)
@@ -230,7 +230,7 @@ def test_pending_without_admission_fails_closed(tmp_path: Path) -> None:
WorkflowRunRecord,
)
ownership = SchedulerOwnership(tmp_path / "sched", owner="test").acquire()
ownership = SchedulerOwnership(tmp_path, owner="test").acquire()
try:
sched, store, runs = _harness(tmp_path, ownership, script={"*": "hang"})
intended = ts(2026, 9, 8, 12, 0)
@@ -260,7 +260,7 @@ def test_pending_without_admission_fails_closed(tmp_path: Path) -> None:
def test_executing_admitted_is_abandoned_by_recovery(tmp_path: Path) -> None:
ownership = SchedulerOwnership(tmp_path / "sched", owner="test").acquire()
ownership = SchedulerOwnership(tmp_path, owner="test").acquire()
try:
sched, store, runs = _harness(tmp_path, ownership, script={"*": "hang"})
intended = ts(2026, 9, 8, 12, 0)
@@ -289,7 +289,7 @@ def test_executing_admitted_is_abandoned_by_recovery(tmp_path: Path) -> None:
def test_settle_hanging_run_persists_and_clears(tmp_path: Path) -> None:
ownership = SchedulerOwnership(tmp_path / "sched", owner="test").acquire()
ownership = SchedulerOwnership(tmp_path, owner="test").acquire()
try:
sched, store, runs = _harness(tmp_path, ownership, script={"*": "hang"})
intended = ts(2026, 9, 8, 12, 0)
@@ -350,7 +350,7 @@ def _child_poll_and_die(
capacity=4,
preparer=_Prep(_Dict({"dep-1": {"rev": 1, "required": []}}), _env),
dispatcher=_SD({"*": killer}),
ownership=_Own(base / "sched", owner="child").acquire(),
ownership=_Own(base, owner="child").acquire(),
)
sched.poll(intended)
@@ -376,7 +376,7 @@ def test_subprocess_death_after_side_effect_dispatches_once(tmp_path: Path) -> N
# Restart with fresh objects: the side effect count stays one and the run
# is abandoned, never redispatched.
ownership = SchedulerOwnership(root / "sched", owner="parent").acquire()
ownership = SchedulerOwnership(root, owner="parent").acquire()
try:
sched, store, runs = _harness(root, ownership, script={"*": "hang"})
sched.sources["a"] = OneShotSource(intended)