feat(perf): chantier B — instantanés SQLite et rafraîchisseur d'arrière-plan
- Table snapshots + écriture traversante du cache client, hydratation au démarrage (SWR : servi + rafraîchi en fond). - Boucle de rafraîchissement (120 s par défaut) : index, étoiles, issues all+open et jalons des projets actifs ; webhook = rafraîchissement immédiat du dépôt ; fraîcheur affichée.
This commit is contained in:
@@ -11,6 +11,7 @@ and upgrades older databases in place (position column, notes
|
||||
updated_at, cleanup of rows carrying an unknown column name).
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
from contextlib import contextmanager
|
||||
@@ -91,6 +92,12 @@ def init_db() -> None:
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS snapshots (
|
||||
key TEXT PRIMARY KEY,
|
||||
payload TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_events_repo
|
||||
ON board_events(repo_full_name, issue_number, created_at);
|
||||
"""
|
||||
@@ -292,6 +299,48 @@ def set_kv(key: str, value: str) -> None:
|
||||
)
|
||||
|
||||
|
||||
# ── Snapshots (chantier B, 0.22.0) ─────────────────────────
|
||||
# Persisted copies of the Gitea list responses the pages read
|
||||
# (repos, issues, milestones, starred). The client cache is
|
||||
# hydrated from these rows at startup, so even the first page
|
||||
# after a restart renders from local data while the background
|
||||
# refresher re-fetches from Gitea.
|
||||
|
||||
def save_snapshot(key: str, payload) -> None:
|
||||
with get_db() as conn:
|
||||
conn.execute(
|
||||
"INSERT INTO snapshots (key, payload, updated_at) "
|
||||
"VALUES (?, ?, datetime('now')) "
|
||||
"ON CONFLICT(key) DO UPDATE SET payload = excluded.payload, "
|
||||
"updated_at = excluded.updated_at",
|
||||
(key, json.dumps(payload)),
|
||||
)
|
||||
|
||||
|
||||
def load_snapshots() -> dict:
|
||||
"""All snapshots as {key: (payload, updated_at_utc_str)}."""
|
||||
with get_db() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT key, payload, updated_at FROM snapshots"
|
||||
).fetchall()
|
||||
out = {}
|
||||
for row in rows:
|
||||
try:
|
||||
out[row["key"]] = (json.loads(row["payload"]), row["updated_at"])
|
||||
except (ValueError, TypeError):
|
||||
continue
|
||||
return out
|
||||
|
||||
|
||||
def latest_snapshot_at() -> str | None:
|
||||
"""UTC timestamp (SQLite format) of the freshest snapshot."""
|
||||
with get_db() as conn:
|
||||
row = conn.execute(
|
||||
"SELECT MAX(updated_at) AS latest FROM snapshots"
|
||||
).fetchone()
|
||||
return row["latest"] if row else None
|
||||
|
||||
|
||||
# ── Event journal ──────────────────────────────────────────
|
||||
|
||||
EVENT_TYPES = ("created", "moved", "closed", "reopened", "commented", "rule")
|
||||
|
||||
Reference in New Issue
Block a user