lidar-maps : navigation en cache seule et pyramide entretenue en tâche de fond

Sur une petite machine (Raspberry Pi), LIDAR_TILE_CACHE_ONLY sert les tuiles
depuis le cache uniquement (tuile absente = transparente non mémorisable,
X-Tile-Pending) et LIDAR_TILE_BACKGROUND fait surveiller les dalles par un
sondeur : chaque dalle nouvelle ou régénérée par le worker remet sa pyramide
en file, rendue à basse priorité et au ralenti. Scan et état pilotables via
/api/map/background, pré-calcul exhaustif toujours via /api/map/warm.
This commit is contained in:
Antoine Jacquin
2026-09-23 19:05:58 +02:00
parent 053eb2f529
commit 900332cdbc
5 changed files with 416 additions and 10 deletions

View File

@ -530,3 +530,68 @@ def test_worker_limits_are_configurable(monkeypatch):
monkeypatch.delenv("LIDAR_TILE_FETCH_WORKERS", raising=False)
importlib.reload(tiles)
importlib.reload(mapserve)
def _reset_bg(mapserve):
mapserve._bg["queue"].clear()
mapserve._bg["queued"].clear()
mapserve._bg["snapshot"] = None
mapserve._bg["stats"].update(rendues=0, a_jour=0, vides=0, scans=0,
dernier_scan=None, ajouts_dernier_scan=0)
def test_tile_cache_only_never_renders(tmp_path, monkeypatch):
"""Mode cache seule : tuile manquante = transparente non mémorisable."""
import lidar_pipeline.mapserve as mapserve
from lidar_pipeline import tiles
_make_dalle(tmp_path, 1054, 6882, ["slope"])
monkeypatch.setattr(mapserve, "OUTPUT_DIR", tmp_path)
tiles.source_index(tmp_path, force=True)
monkeypatch.setenv("LIDAR_TILE_CACHE_ONLY", "1")
z = 15
x, y = _tile_of_cell(1054, 6882, z)
resp = asyncio.run(mapserve.tile("slope", z, x, f"{y}.png"))
assert resp.headers["X-Tile-Pending"] == "1"
assert resp.headers["X-Tile-Empty"] == "1"
assert resp.headers["Cache-Control"] == "no-store"
assert not tiles.tile_cache_path(tmp_path, "slope", z, x, y).exists()
# Une fois rendue par ailleurs : servie depuis le cache, mémorisable
tiles.get_tile(tmp_path, "slope", z, x, y)
resp = asyncio.run(mapserve.tile("slope", z, x, f"{y}.png", v="s"))
assert resp.headers["X-Tile-Empty"] == "0"
assert "X-Tile-Pending" not in resp.headers
assert "immutable" in resp.headers["Cache-Control"]
def test_background_scan_detects_and_fills(tmp_path, monkeypatch):
"""La maintenance détecte les dalles, remplit la pyramide, puis se tait."""
import lidar_pipeline.mapserve as mapserve
from lidar_pipeline import tiles
_make_dalle(tmp_path, 1054, 6882, ["slope"])
monkeypatch.setattr(mapserve, "OUTPUT_DIR", tmp_path)
monkeypatch.setenv("LIDAR_TILE_BACKGROUND_MAX_Z", "14")
monkeypatch.setenv("LIDAR_TILE_BACKGROUND_SCALE", "1")
monkeypatch.setenv("LIDAR_TILE_BACKGROUND_FMT", "png")
monkeypatch.setenv("LIDAR_TILE_BACKGROUND_PAUSE", "0")
_reset_bg(mapserve)
try:
# Premier scan : tout est nouveau, bas niveaux en tête de file
assert mapserve.background_scan(tmp_path) > 0
zs = [t[1] for t in mapserve._bg["queue"]]
assert zs == sorted(zs) and max(zs) <= 14
processed = 0
while mapserve._bg["queue"] and processed < 1000:
mapserve._bg_process_one()
processed += 1
assert not mapserve._bg["queue"]
assert mapserve._bg["stats"]["rendues"] > 0
x, y = _tile_of_cell(1054, 6882, 14)
assert tiles.tile_cache_path(
tmp_path, "slope", 14, x, y, 1, "png").exists()
# Rien n'a changé : plus aucun ajout
assert mapserve.background_scan(tmp_path) == 0
# Une dalle nouvelle (worker) : sa pyramide repart seule en file
_make_dalle(tmp_path, 1055, 6882, ["slope"])
assert mapserve.background_scan(tmp_path) > 0
finally:
_reset_bg(mapserve)