diff --git a/docs/docker.md b/docs/docker.md index af06d648..f9ed5c66 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -14,7 +14,7 @@ This page covers common Docker workflows and troubleshooting. Simons typical workflow. -While making code changes, I do this. +While making code changes, I use `./rebuild.sh`, that does this: ```bash docker compose down --remove-orphans diff --git a/frontend_multi_user/src/app.py b/frontend_multi_user/src/app.py index 253ba1ca..6a952715 100644 --- a/frontend_multi_user/src/app.py +++ b/frontend_multi_user/src/app.py @@ -1971,6 +1971,41 @@ def _build_plan_telemetry( return telemetry + def _get_database_size_info(self) -> dict[str, Any]: + """Query PostgreSQL for database size and per-table breakdown.""" + from sqlalchemy import text + info: dict[str, Any] = {"error": None, "database_name": None, "total_bytes": 0, "total_mb": 0.0, "tables": []} + try: + with self.db.engine.connect() as conn: + row = conn.execute(text( + "SELECT current_database(), pg_database_size(current_database())" + )).fetchone() + if row: + info["database_name"] = row[0] + info["total_bytes"] = row[1] + info["total_mb"] = round(row[1] / (1024 * 1024), 2) + + tables = conn.execute(text( + "SELECT schemaname, tablename, " + "pg_total_relation_size(schemaname || '.' || tablename) AS total_bytes, " + "pg_relation_size(schemaname || '.' || tablename) AS table_bytes, " + "pg_total_relation_size(schemaname || '.' || tablename) - pg_relation_size(schemaname || '.' || tablename) AS index_bytes " + "FROM pg_tables WHERE schemaname = 'public' " + "ORDER BY total_bytes DESC" + )).fetchall() + for t in tables: + info["tables"].append({ + "name": t[1], + "total_bytes": t[2], + "total_mb": round(t[2] / (1024 * 1024), 2), + "table_mb": round(t[3] / (1024 * 1024), 2), + "index_mb": round(t[4] / (1024 * 1024), 2), + }) + except Exception as e: + logger.exception("Failed to query database size") + info["error"] = str(e) + return info + def _build_reconciliation_report(self, max_tasks: int, tolerance_usd: float) -> tuple[list[dict[str, Any]], dict[str, Any]]: tasks = ( PlanItem.query @@ -2942,6 +2977,15 @@ def admin_reconciliation(): refresh_seconds=refresh_seconds, ) + @self.app.route('/admin/db-size') + @admin_required + def admin_db_size(): + size_info = self._get_database_size_info() + return self.admin.index_view.render( + "admin/db_size.html", + size_info=size_info, + ) + @self.app.route('/ping/stream') @login_required def ping_stream(): diff --git a/frontend_multi_user/templates/admin/db_size.html b/frontend_multi_user/templates/admin/db_size.html new file mode 100644 index 00000000..2a2866c0 --- /dev/null +++ b/frontend_multi_user/templates/admin/db_size.html @@ -0,0 +1,121 @@ +{% extends 'admin/master.html' %} + +{% block head_css %} + {{ super() }} + +{% endblock %} + +{% block body %} +
+

Database Size

+ + {% if size_info.error %} +
+ Error querying database size: {{ size_info.error }} +
+ {% else %} +
+
+
{{ size_info.total_mb }} MB
+
Total database size
+
+
+
Database: {{ size_info.database_name }}
+
+
+ + {% if size_info.tables %} +

Per-table breakdown

+ + + + + + + + + + + + {% for t in size_info.tables %} + + + + + + + + {% endfor %} + +
TableTotal (MB)Data (MB)Indexes (MB)
{{ t.name }}{{ t.total_mb }}{{ t.table_mb }}{{ t.index_mb }} + {% if size_info.tables[0].total_bytes > 0 %} +
+ {% endif %} +
+ {% endif %} + {% endif %} +
+{% endblock %} diff --git a/frontend_multi_user/templates/admin/index.html b/frontend_multi_user/templates/admin/index.html index 8bb79731..4fd14ebd 100644 --- a/frontend_multi_user/templates/admin/index.html +++ b/frontend_multi_user/templates/admin/index.html @@ -75,5 +75,9 @@

Primary links

Reconciliation and drift detection
Compare billed usage cost vs tracked inference cost per task.
+ + Database Size +
View PostgreSQL disk space usage and per-table breakdown.
+
{% endblock %} diff --git a/rebuild.sh b/rebuild.sh new file mode 100755 index 00000000..92f26293 --- /dev/null +++ b/rebuild.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -e +docker compose down --remove-orphans +docker compose build --no-cache +docker compose up