feat(settings): Settings → System shows table sizes and what the last cleanup removed (#5469)
#5469 "Settings → System: table sizes and what the last cleanup removed". - Storage: each table's size on disk (pg_total_relation_size, indexes and TOAST included) and Postgres's row estimate (reltuples), largest first, the 15 largest by name and the rest summed, under the database's total size. Read from the catalog only, never by counting rows. - Last cleanup: when it ran, how long it took, and what each pass removed (each aged table, run log files, the metric and Docker rollups, the log ring), or "Nothing was past its window". run_cleanup now returns that summary and keeps it as the cleanup.last_run setting, as reports.last_sent_at does; cleanup_secs (#5467) is recorded from the same figure. - A hint links to where each retention window is set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -67,3 +67,42 @@ async def process_health(db) -> dict:
|
||||
if (by["open_fds_pct"]["now"] or 0) >= FD_WARN_PCT:
|
||||
problems.append(f"open files at {by['open_fds_pct']['now']:.0f}% of the limit")
|
||||
return {"rows": rows, "problems": problems, "seen": any(r["at"] for r in rows)}
|
||||
|
||||
|
||||
# How many tables Settings → System lists by name; the rest are summed.
|
||||
TABLES_SHOWN = 15
|
||||
|
||||
|
||||
async def table_sizes(db) -> dict:
|
||||
"""Steward's tables by size on disk, largest first (#5469), from Postgres's
|
||||
own catalog: pg_total_relation_size (indexes and TOAST included) and the
|
||||
planner's row estimate (reltuples; None for a table never analysed).
|
||||
|
||||
Returns {"total": bytes of the whole database, "tables": [{name, bytes,
|
||||
rows}] for the TABLES_SHOWN largest, "rest": {count, bytes} of the others}."""
|
||||
from sqlalchemy import text
|
||||
rows = (await db.execute(text(
|
||||
"SELECT c.relname, pg_total_relation_size(c.oid), c.reltuples::bigint "
|
||||
"FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace "
|
||||
"WHERE c.relkind IN ('r', 'p') AND n.nspname = current_schema() "
|
||||
"ORDER BY 2 DESC"))).all()
|
||||
total = (await db.execute(text("SELECT pg_database_size(current_database())"))).scalar()
|
||||
tables = [{"name": name, "bytes": size, "rows": est if est is not None and est >= 0 else None}
|
||||
for name, size, est in rows]
|
||||
rest = tables[TABLES_SHOWN:]
|
||||
return {"total": total, "tables": tables[:TABLES_SHOWN],
|
||||
"rest": {"count": len(rest), "bytes": sum(t["bytes"] for t in rest)}}
|
||||
|
||||
|
||||
async def last_cleanup(db) -> dict | None:
|
||||
"""The last hourly cleanup that finished (#5469), as core/cleanup.py kept
|
||||
it: {"at": datetime, "secs", "removed": [(what, n)] with n > 0, "passes":
|
||||
how many passes ran}. None before the first one finishes."""
|
||||
from datetime import datetime
|
||||
from steward.core.settings import get_setting
|
||||
run = await get_setting(db, "cleanup.last_run") or {}
|
||||
if not run.get("at"):
|
||||
return None
|
||||
removed = [(what, n) for what, n in run.get("removed") or []]
|
||||
return {"at": datetime.fromisoformat(run["at"]), "secs": run.get("secs"),
|
||||
"removed": [(what, n) for what, n in removed if n], "passes": len(removed)}
|
||||
|
||||
Reference in New Issue
Block a user