feat: réutiliser le DuckDB existant si le bootstrap échoue (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -118,13 +118,24 @@ def _ensure_database() -> Path:
|
|||||||
db_path = Path(os.getenv("DUCKDB_PATH", "./decp.duckdb"))
|
db_path = Path(os.getenv("DUCKDB_PATH", "./decp.duckdb"))
|
||||||
parquet_path = os.getenv("DATA_FILE_PARQUET_PATH", "")
|
parquet_path = os.getenv("DATA_FILE_PARQUET_PATH", "")
|
||||||
lock_path = db_path.with_suffix(".duckdb.lock")
|
lock_path = db_path.with_suffix(".duckdb.lock")
|
||||||
|
db_exists = db_path.exists()
|
||||||
|
|
||||||
with open(lock_path, "w") as lock_fd:
|
with open(lock_path, "w") as lock_fd:
|
||||||
fcntl.flock(lock_fd, fcntl.LOCK_EX)
|
fcntl.flock(lock_fd, fcntl.LOCK_EX)
|
||||||
if should_rebuild(db_path, parquet_path):
|
try:
|
||||||
build_database(db_path)
|
if should_rebuild(db_path, parquet_path):
|
||||||
else:
|
build_database(db_path)
|
||||||
logger.debug("Base de données déjà disponible et à jour.")
|
else:
|
||||||
|
logger.debug("Base de données déjà disponible et à jour.")
|
||||||
|
except Exception as e:
|
||||||
|
if db_exists:
|
||||||
|
logger.error(
|
||||||
|
f"Bootstrap données KO ({e}). "
|
||||||
|
f"Réutilisation du DuckDB existant : {db_path}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logger.critical("Aucune base DuckDB et reconstruction impossible.")
|
||||||
|
raise
|
||||||
return db_path
|
return db_path
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -312,3 +312,59 @@ def test_concurrent_build_serialized(tmp_path, monkeypatch):
|
|||||||
assert errors == []
|
assert errors == []
|
||||||
assert db_path.exists()
|
assert db_path.exists()
|
||||||
assert not tmp_path_artifact.exists()
|
assert not tmp_path_artifact.exists()
|
||||||
|
|
||||||
|
|
||||||
|
def _raise(*args, **kwargs):
|
||||||
|
raise RuntimeError("boom")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ensure_database_reuses_db_when_should_rebuild_raises(tmp_path, monkeypatch):
|
||||||
|
import src.db as db
|
||||||
|
|
||||||
|
dbf = tmp_path / "decp.duckdb"
|
||||||
|
dbf.write_bytes(b"existing")
|
||||||
|
monkeypatch.setenv("DUCKDB_PATH", str(dbf))
|
||||||
|
monkeypatch.setenv("DATA_FILE_PARQUET_PATH", "http://unreachable")
|
||||||
|
monkeypatch.setattr(db, "should_rebuild", _raise)
|
||||||
|
result = db._ensure_database() # ne doit pas lever
|
||||||
|
assert result == dbf
|
||||||
|
assert dbf.read_bytes() == b"existing"
|
||||||
|
|
||||||
|
|
||||||
|
def test_ensure_database_reuses_db_when_build_raises(tmp_path, monkeypatch):
|
||||||
|
import src.db as db
|
||||||
|
|
||||||
|
dbf = tmp_path / "decp.duckdb"
|
||||||
|
dbf.write_bytes(b"existing")
|
||||||
|
monkeypatch.setenv("DUCKDB_PATH", str(dbf))
|
||||||
|
monkeypatch.setenv("DATA_FILE_PARQUET_PATH", "http://unreachable")
|
||||||
|
monkeypatch.setattr(db, "should_rebuild", lambda *a, **k: True)
|
||||||
|
monkeypatch.setattr(db, "build_database", _raise)
|
||||||
|
db._ensure_database() # ne doit pas lever
|
||||||
|
assert dbf.read_bytes() == b"existing"
|
||||||
|
|
||||||
|
|
||||||
|
def test_ensure_database_raises_on_cold_start(tmp_path, monkeypatch):
|
||||||
|
import src.db as db
|
||||||
|
|
||||||
|
dbf = tmp_path / "decp.duckdb" # n'existe pas
|
||||||
|
monkeypatch.setenv("DUCKDB_PATH", str(dbf))
|
||||||
|
monkeypatch.setenv("DATA_FILE_PARQUET_PATH", "http://unreachable")
|
||||||
|
monkeypatch.setattr(db, "should_rebuild", lambda *a, **k: True)
|
||||||
|
monkeypatch.setattr(db, "build_database", _raise)
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
db._ensure_database()
|
||||||
|
|
||||||
|
|
||||||
|
def test_ensure_database_builds_when_needed(tmp_path, monkeypatch):
|
||||||
|
import src.db as db
|
||||||
|
|
||||||
|
dbf = tmp_path / "decp.duckdb"
|
||||||
|
dbf.write_bytes(b"old")
|
||||||
|
monkeypatch.setenv("DUCKDB_PATH", str(dbf))
|
||||||
|
monkeypatch.setenv("DATA_FILE_PARQUET_PATH", "http://x")
|
||||||
|
called = {}
|
||||||
|
monkeypatch.setattr(db, "should_rebuild", lambda *a, **k: True)
|
||||||
|
monkeypatch.setattr(db, "build_database", lambda p: called.setdefault("built", p))
|
||||||
|
db._ensure_database()
|
||||||
|
assert called.get("built") == dbf
|
||||||
|
|||||||
Reference in New Issue
Block a user