refactor(config_store): replace generic key/value table with explicit schema
test / stage-firecracker-inputs (push) Successful in 2s
test / integration-docker (push) Successful in 17s
Update Quality Badges / update-badges (push) Failing after 42s
lint / lint (push) Successful in 47s
test / unit (push) Successful in 1m41s
test / build-infra (push) Successful in 3m43s
test / integration-firecracker (push) Successful in 1m28s
test / coverage (push) Successful in 1m29s
test / publish-infra (push) Successful in 1m49s

Switch orchestrator_config from a generic key/text store to a typed
single-row table with a dedicated teardown_timeout_seconds REAL column.
The CHECK (id = 1) constraint enforces at most one config row.

Remove TEARDOWN_TIMEOUT_KEY constant; update OrchestratorConfigStore to
expose get/set/delete_teardown_timeout_seconds() instead of the generic
get/set/delete(key). Resolving the DB value in resolve_teardown_timeout()
no longer needs a float() conversion since the column is already REAL.
This commit was merged in pull request #436.
This commit is contained in:
2026-07-21 04:26:00 +00:00
committed by didericis
parent 853b6d1678
commit 1f192d785a
2 changed files with 38 additions and 45 deletions
+21 -26
View File
@@ -1,4 +1,4 @@
"""Per-host orchestrator configuration store (key/value settings in bot-bottle.db).
"""Per-host orchestrator configuration store (settings in bot-bottle.db).
Co-tenants the shared `bot-bottle.db` via the `DbStore` framework. Settings
are readable by the host launch path directly (no HTTP round-trip to the
@@ -15,7 +15,6 @@ from ..db_store import DbStore
from ..migrations import TableMigrations
from ..paths import host_db_path
TEARDOWN_TIMEOUT_KEY = "teardown_timeout_seconds"
TEARDOWN_TIMEOUT_ENV = "BOT_BOTTLE_ORCHESTRATOR_TEARDOWN_TIMEOUT_SECONDS"
DEFAULT_TEARDOWN_TIMEOUT_SECONDS = 30.0
@@ -24,8 +23,8 @@ _MIGRATIONS = TableMigrations(
[
"""
CREATE TABLE IF NOT EXISTS orchestrator_config (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
id INTEGER PRIMARY KEY CHECK (id = 1),
teardown_timeout_seconds REAL
)
""",
],
@@ -33,7 +32,7 @@ _MIGRATIONS = TableMigrations(
class OrchestratorConfigStore(DbStore):
"""Key/value store for orchestrator settings in the shared host DB."""
"""Orchestrator settings in the shared host DB."""
def __init__(self, db_path: Path | None = None) -> None:
super().__init__(db_path or host_db_path(), _MIGRATIONS)
@@ -43,31 +42,33 @@ class OrchestratorConfigStore(DbStore):
conn.execute("PRAGMA busy_timeout=5000")
return conn
def get(self, key: str) -> str | None:
"""Return the value for `key`, or None if absent."""
def get_teardown_timeout_seconds(self) -> float | None:
"""Return the configured teardown timeout, or None if not set."""
try:
with self._connection() as conn:
row = conn.execute(
"SELECT value FROM orchestrator_config WHERE key = ?", (key,)
"SELECT teardown_timeout_seconds FROM orchestrator_config WHERE id = 1"
).fetchone()
except sqlite3.OperationalError:
return None
return row["value"] if row else None
return row["teardown_timeout_seconds"] if row else None
def set(self, key: str, value: str) -> None:
"""Upsert a setting."""
def set_teardown_timeout_seconds(self, value: float) -> None:
"""Persist the teardown timeout."""
with self._connection() as conn:
conn.execute(
"INSERT OR REPLACE INTO orchestrator_config (key, value) VALUES (?, ?)",
(key, value),
"INSERT OR REPLACE INTO orchestrator_config"
" (id, teardown_timeout_seconds) VALUES (1, ?)",
(value,),
)
self._chmod()
def delete(self, key: str) -> bool:
"""Remove a setting. Returns True if the key existed."""
def delete_teardown_timeout_seconds(self) -> bool:
"""Clear the stored teardown timeout. Returns True if a value existed."""
with self._connection() as conn:
cur = conn.execute(
"DELETE FROM orchestrator_config WHERE key = ?", (key,)
"UPDATE orchestrator_config SET teardown_timeout_seconds = NULL"
" WHERE id = 1 AND teardown_timeout_seconds IS NOT NULL"
)
return cur.rowcount > 0
@@ -76,7 +77,7 @@ def resolve_teardown_timeout(db_path: Path | None = None) -> float:
"""Return the teardown timeout to use, in priority order:
1. ``BOT_BOTTLE_ORCHESTRATOR_TEARDOWN_TIMEOUT_SECONDS`` env var
2. ``teardown_timeout_seconds`` key in the orchestrator config DB
2. ``teardown_timeout_seconds`` in the orchestrator config DB
3. ``DEFAULT_TEARDOWN_TIMEOUT_SECONDS`` (30 s)
"""
raw = os.environ.get(TEARDOWN_TIMEOUT_ENV, "").strip()
@@ -91,14 +92,9 @@ def resolve_teardown_timeout(db_path: Path | None = None) -> float:
store = OrchestratorConfigStore(db_path)
if not store.is_migrated():
store.migrate()
raw_db = store.get(TEARDOWN_TIMEOUT_KEY)
if raw_db is not None:
try:
value = float(raw_db)
if value > 0:
return value
except ValueError:
pass
db_value = store.get_teardown_timeout_seconds()
if db_value is not None and db_value > 0:
return db_value
return DEFAULT_TEARDOWN_TIMEOUT_SECONDS
@@ -106,7 +102,6 @@ def resolve_teardown_timeout(db_path: Path | None = None) -> float:
__all__ = [
"OrchestratorConfigStore",
"resolve_teardown_timeout",
"TEARDOWN_TIMEOUT_KEY",
"TEARDOWN_TIMEOUT_ENV",
"DEFAULT_TEARDOWN_TIMEOUT_SECONDS",
]