fix(cron): keep store state another still-ticked profile shares through a symlink
Two profiles whose cron/ resolves to one store share a store key; when one left, its departure dropped the degraded record the remaining profile still needed (gauge flipped to writable, a second outage notice, and the earlier outage start lost for one-shot cover). Departed stores now exclude the ones still ticked. The notices test pins it (red without the set difference).
This commit is contained in:
@@ -40,7 +40,7 @@ def register_ticked_homes(homes) -> None:
|
||||
live until process exit, so serving (or churning) many profiles leaks one ThreadPoolExecutor
|
||||
and its worker threads per home ever ticked.
|
||||
"""
|
||||
from cron.store_health import forget_homes, store_key
|
||||
from cron.store_health import forget_stores, store_key
|
||||
|
||||
resolved, stores = {}, {}
|
||||
for home in homes:
|
||||
@@ -50,7 +50,8 @@ def register_ticked_homes(homes) -> None:
|
||||
stores[key] = store_key(path)
|
||||
with _ticked_lock:
|
||||
departed = set(_ticked_homes) - set(resolved)
|
||||
departed_stores = [_ticked_stores[k] for k in departed if k in _ticked_stores]
|
||||
# A store another still-ticked profile reaches (cron/ symlinked to one place) keeps its state.
|
||||
departed_stores = {_ticked_stores[k] for k in departed if k in _ticked_stores} - set(stores.values())
|
||||
_ticked_homes.clear()
|
||||
_ticked_homes.update(resolved)
|
||||
_ticked_stores.clear()
|
||||
@@ -59,7 +60,7 @@ def register_ticked_homes(homes) -> None:
|
||||
# Late import: cron.scheduler imports this module.
|
||||
from cron.scheduler import discard_parallel_pools
|
||||
discard_parallel_pools(departed)
|
||||
forget_homes(departed_stores)
|
||||
forget_stores(departed_stores)
|
||||
|
||||
|
||||
def ticked_homes() -> dict:
|
||||
|
||||
@@ -456,7 +456,11 @@ def test_unwritable_store_is_shown_in_cron_status_and_announced_once(cron_store,
|
||||
assert any(r.levelname == "WARNING" and "unwritable notice for" in r.getMessage() for r in caplog.records)
|
||||
from cron import scheduler_ownership # the profile leaves this gateway, its home already deleted
|
||||
monkeypatch.setattr(scheduler_ownership, "_ticked_homes", {})
|
||||
scheduler_ownership.register_ticked_homes([profile])
|
||||
sibling = cron_store / "sibling" # a second profile whose cron/ reaches the same store
|
||||
sibling.mkdir()
|
||||
(sibling / "cron").symlink_to(cron_dir, target_is_directory=True)
|
||||
scheduler_ownership.register_ticked_homes([profile, sibling])
|
||||
scheduler_ownership.register_ticked_homes([profile]) # sibling leaves; the store is still ticked
|
||||
assert store_health.degraded_record(cron_dir) is not None
|
||||
shutil.rmtree(profile) # removes the cron/ symlink, never the store it points at
|
||||
scheduler_ownership.register_ticked_homes([])
|
||||
|
||||
Reference in New Issue
Block a user