Files
admin 5f695ebe2a fix: kein WAL mehr, damit die read-only Web-App die DB öffnen kann
Eine readonly-Verbindung (web-Container) kann eine WAL-Datenbank ohne aktiven
Writer/-shm nicht öffnen -> "attempt to write a readonly database", die Seite
blieb leer. Da collector (Writer) und web (Reader) getrennte Prozesse sind und
der collector keine Dauerverbindung hält, existiert im Ruhezustand kein -shm.

- collector/db.py + schema.sql: WAL entfernt (Rollback-Journal als Default);
  readonly-Reads sind damit jederzeit möglich.
- web/lib/db.ts: busy_timeout=5s, falls gerade geschrieben wird.

Bestehende DB einmalig umstellen: PRAGMA journal_mode=DELETE;

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 15:28:08 +02:00

54 lines
1.7 KiB
Python

"""SQLite-Helfer für den Collector (Schema-Init + Schreibzugriffe)."""
import os
import sqlite3
from datetime import datetime
from pathlib import Path
SCHEMA_PATH = Path(__file__).with_name("schema.sql")
def get_db_path() -> str:
return os.environ.get("DB_PATH", "/data/charges.db")
def connect() -> sqlite3.Connection:
path = get_db_path()
Path(path).parent.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(path)
conn.row_factory = sqlite3.Row
# Bewusst KEIN WAL: Der web-Container liest die DB read-only aus einem
# anderen Prozess. Eine readonly-Verbindung kann eine WAL-Datenbank ohne
# aktiven Writer/-shm nicht öffnen ("attempt to write a readonly database").
# Rollback-Journal (Default) lässt readonly-Reads jederzeit zu.
return conn
def init_db() -> None:
"""Legt Schema idempotent an und setzt install_date beim ersten Start."""
schema = SCHEMA_PATH.read_text(encoding="utf-8")
conn = connect()
try:
conn.executescript(schema)
conn.execute(
"INSERT OR IGNORE INTO meta (key, value) VALUES ('install_date', ?)",
(datetime.now().isoformat(timespec="seconds"),),
)
conn.commit()
finally:
conn.close()
def insert_charge(start_time: str, end_time: str, duration_s: int, energy_wh: float) -> None:
conn = connect()
try:
conn.execute(
"""INSERT INTO charges (start_time, end_time, duration_s, energy_wh, created_at)
VALUES (?, ?, ?, ?, ?)""",
(start_time, end_time, duration_s, energy_wh,
datetime.now().isoformat(timespec="seconds")),
)
conn.commit()
finally:
conn.close()