fix(database): open backend so records actually persist and reload (#1209)

* fix(database): open backend so records actually persist and reload

Measurement and prediction records were never persisted to the
configured database backend (e.g. LMDB). They only survived while the
process was running; every restart lost the accumulated history. For
LoadAkkudoktorAdjusted this silently zeroed the measurement-based
adjustment (the adjusted load forecast collapsed onto the raw mean).

Root cause: `db_enabled` is defined as `database.is_open`, and every
database code path (initialization, load, save, insert) is guarded behind
`db_enabled`. Nothing ever opened the backend first -- the only lazy open
(via `_run_db`) was unreachable because those calls sit behind the same
guard. The backend therefore stayed closed, `db_enabled` stayed False,
and all writes fell through to the JSON file fallback, which only holds
the current in-memory snapshot and is not reloaded into the record store
on startup.

Fix: explicitly open the configured backend in `_db_ensure_initialized`
before the `db_enabled` gate, wrapped in try/except so a failure degrades
gracefully to file storage.

Verified via an A/B test (identical persisted config, push -> save ->
restart): without the fix the backend reports enabled=false and data is
lost on restart; with the fix the backend is enabled, records persist to
LMDB, and reload correctly after restart.

* fix(database): skip disabled providers and avoid open retry loop

Address review feedback:
- Skip opening the backend for disabled providers (None/"NoDB"), whose
  is_open is always False and would otherwise be reopened on every call.
- Add a one-shot _db_open_attempted flag so a closed/failed backend is not
  retried (and re-logged) on every record operation.
- Add tests covering that NoDB never calls open() and that an unavailable
  backend does not raise per operation and is opened at most once.

* fix(database): drop file-storage-fallback wording from open failure log

---------

Co-authored-by: Cornelius Mund <cornim@users.noreply.github.com>
This commit is contained in:
Cornelius Mund
2026-08-01 12:46:00 +02:00
committed by GitHub
co-authored by Cornelius Mund
parent 1905682113
commit b59012c1f7
2 changed files with 83 additions and 0 deletions
+29
View File
@@ -620,8 +620,37 @@ class DatabaseRecordProtocolMixin(
self._db_metadata = None
self._db_storage_initialized: bool = False
# Whether an explicit backend open has already been attempted.
# One-shot per init so a closed/failed backend is not retried on
# every record operation. Re-armed when DB state is reset.
self._db_open_attempted: bool = False
self._db_initialized: bool = True
# Ensure the configured database backend is actually opened.
# `db_enabled` reflects `database.is_open`, and every DB code path is guarded
# behind `db_enabled`. Without an explicit open here the backend is never
# opened (lazy open via `_run_db` is unreachable), so records would only ever
# persist to the JSON file fallback and never reload into memory on startup.
#
# Skip disabled providers (None/"NoDB"): persistence is intentionally off and
# `NoDB.is_open` is always False, so opening it would run on every call. Only
# attempt the open once; on failure we log without retrying (and re-logging)
# on every subsequent record operation.
provider = self.config.database.provider
if (
provider not in (None, "NoDB")
and not self.database.is_open
and not self._db_open_attempted
):
self._db_open_attempted = True
try:
await self.database.open(namespace=self.db_namespace())
except Exception:
logger.exception(
f"Could not open database backend for namespace '{self.db_namespace()}'."
)
if not self._db_storage_initialized and self.db_enabled:
# Metadata
existing_metadata = await self._db_load_metadata()