mirror of
https://github.com/Horizontal42/netsleuth.git
synced 2026-11-11 01:02:10 +03:00
bgp: clamp cache age to zero against windows mtime clock skew
time.time() - path.stat().st_mtime went negative under load when NTFS stamped a write's mtime slightly ahead of the wall clock read a moment later, making a ttl_hours=0 cache lookup serve stale data instead of refetching. surfaced as a flaky failure in test_cached_json_refetches_once_the_entry_expires during the full suite run before task 40's smoke test.
This commit is contained in:
parent
0d6d5405b3
commit
10c5939bcb
2 changed files with 19 additions and 1 deletions
|
|
@ -160,7 +160,8 @@ async def cached_json(
|
||||||
fetch: Callable[[], Awaitable[dict]],
|
fetch: Callable[[], Awaitable[dict]],
|
||||||
) -> dict:
|
) -> dict:
|
||||||
path = Path(cache_dir) / f"{key}.json"
|
path = Path(cache_dir) / f"{key}.json"
|
||||||
if path.exists() and (time.time() - path.stat().st_mtime) < ttl_hours * 3600:
|
age = max(0.0, time.time() - path.stat().st_mtime) if path.exists() else None
|
||||||
|
if age is not None and age < ttl_hours * 3600:
|
||||||
try:
|
try:
|
||||||
return json.loads(path.read_text(encoding="utf-8"))
|
return json.loads(path.read_text(encoding="utf-8"))
|
||||||
except (OSError, ValueError):
|
except (OSError, ValueError):
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,23 @@ async def test_cached_json_refetches_once_the_entry_expires(tmp_path: Path):
|
||||||
assert len(calls) == 2
|
assert len(calls) == 2
|
||||||
|
|
||||||
|
|
||||||
|
async def test_cached_json_refetches_when_mtime_reads_ahead_of_now(tmp_path: Path):
|
||||||
|
import os
|
||||||
|
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
async def fetch() -> dict:
|
||||||
|
calls.append(1)
|
||||||
|
return {"value": len(calls)}
|
||||||
|
|
||||||
|
await cached_json(tmp_path, "k", ttl_hours=24, fetch=fetch)
|
||||||
|
future = (tmp_path / "k.json").stat().st_mtime + 5
|
||||||
|
os.utime(tmp_path / "k.json", (future, future))
|
||||||
|
result = await cached_json(tmp_path, "k", ttl_hours=0, fetch=fetch)
|
||||||
|
assert result == {"value": 2}
|
||||||
|
assert len(calls) == 2
|
||||||
|
|
||||||
|
|
||||||
async def test_cached_json_survives_a_corrupt_cache_file(tmp_path: Path):
|
async def test_cached_json_survives_a_corrupt_cache_file(tmp_path: Path):
|
||||||
(tmp_path / "k.json").write_text("{not json", encoding="utf-8")
|
(tmp_path / "k.json").write_text("{not json", encoding="utf-8")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue