check retention
This commit is contained in:
@@ -3,3 +3,7 @@
|
||||
DOCKER_REGISTRY=docker.io
|
||||
DOCKER_IMAGE=myorg/myapp
|
||||
IMAGE_TAG=latest
|
||||
|
||||
# Optional: check retention (limits DB growth)
|
||||
# CHECK_RETENTION_COUNT=5000 # keep last N checks per service (default 5000)
|
||||
# CHECK_RETENTION_DAYS=30 # also delete checks older than N days (0=disabled)
|
||||
|
||||
15
README.md
15
README.md
@@ -42,6 +42,21 @@ docker run -p 8080:8080 -v $(pwd)/data:/app/data myapp:test
|
||||
|
||||
Add services from the dashboard (e.g. `https://example.com`, `google.com:443` for TCP) and view reports.
|
||||
|
||||
### Check Retention
|
||||
|
||||
To limit database growth, the app prunes old checks every 15 minutes:
|
||||
|
||||
| Env var | Default | Description |
|
||||
|---------|---------|-------------|
|
||||
| `CHECK_RETENTION_COUNT` | 5000 | Keep last N checks per service |
|
||||
| `CHECK_RETENTION_DAYS` | 0 (disabled) | Also delete checks older than N days |
|
||||
|
||||
Example: keep 2000 checks per service and drop anything older than 30 days:
|
||||
|
||||
```bash
|
||||
docker run -e CHECK_RETENTION_COUNT=2000 -e CHECK_RETENTION_DAYS=30 ...
|
||||
```
|
||||
|
||||
## Jenkins Pipeline
|
||||
|
||||
The pipeline:
|
||||
|
||||
@@ -141,7 +141,7 @@ def report(service_id):
|
||||
status_filter = request.args.get("status")
|
||||
search = request.args.get("search", "").strip() or None
|
||||
page = max(1, int(request.args.get("page", 1)))
|
||||
per_page = min(100, max(10, int(request.args.get("per_page", 25))))
|
||||
per_page = min(100, max(10, int(request.args.get("per_page", 10))))
|
||||
stats = models.get_report_stats(service_id, from_ts=from_ts, to_ts=to_ts)
|
||||
checks_total = models.get_checks_count(service_id, from_ts=from_ts, to_ts=to_ts, status_filter=status_filter, search=search)
|
||||
checks = models.get_checks(
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
import os
|
||||
import sqlite3
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
DATA_PATH = os.environ.get("DATA_PATH", "/app/data")
|
||||
DB_PATH = Path(DATA_PATH) / "monitor.db"
|
||||
|
||||
# Retention: keep last N checks per service, and optionally drop checks older than N days
|
||||
CHECK_RETENTION_COUNT = int(os.environ.get("CHECK_RETENTION_COUNT", "5000"))
|
||||
CHECK_RETENTION_DAYS = int(os.environ.get("CHECK_RETENTION_DAYS", "0")) or None
|
||||
|
||||
|
||||
def _ensure_data_dir():
|
||||
Path(DATA_PATH).mkdir(parents=True, exist_ok=True)
|
||||
@@ -232,3 +236,38 @@ def get_all_services_for_scheduler():
|
||||
with get_db() as conn:
|
||||
rows = conn.execute("SELECT id, target, protocol, interval_seconds FROM services").fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
def prune_checks_retention() -> int:
|
||||
"""
|
||||
Remove old checks to limit storage. Keeps last CHECK_RETENTION_COUNT per service.
|
||||
If CHECK_RETENTION_DAYS is set, also deletes checks older than that.
|
||||
Returns number of rows deleted.
|
||||
"""
|
||||
with get_db() as conn:
|
||||
deleted = 0
|
||||
# Delete checks older than N days (if configured)
|
||||
if CHECK_RETENTION_DAYS:
|
||||
cutoff = (datetime.now(timezone.utc) - timedelta(days=CHECK_RETENTION_DAYS)).isoformat()
|
||||
cur = conn.execute("DELETE FROM checks WHERE timestamp < ?", (cutoff,))
|
||||
deleted += cur.rowcount
|
||||
|
||||
# Keep only last N checks per service
|
||||
service_ids = [r[0] for r in conn.execute("SELECT id FROM services").fetchall()]
|
||||
for sid in service_ids:
|
||||
# Get ids of checks to keep (most recent N)
|
||||
keep_ids = conn.execute(
|
||||
"SELECT id FROM checks WHERE service_id = ? ORDER BY timestamp DESC LIMIT ?",
|
||||
(sid, CHECK_RETENTION_COUNT),
|
||||
).fetchall()
|
||||
keep_ids = [r[0] for r in keep_ids]
|
||||
if not keep_ids:
|
||||
continue
|
||||
placeholders = ",".join("?" * len(keep_ids))
|
||||
cur = conn.execute(
|
||||
f"DELETE FROM checks WHERE service_id = ? AND id NOT IN ({placeholders})",
|
||||
[sid] + keep_ids,
|
||||
)
|
||||
deleted += cur.rowcount
|
||||
|
||||
return deleted
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
||||
from app.checker import run_check
|
||||
from app.models import get_all_services_for_scheduler
|
||||
from app.models import get_all_services_for_scheduler, prune_checks_retention
|
||||
|
||||
|
||||
def _run_all_checks():
|
||||
@@ -54,4 +54,7 @@ def start_scheduler():
|
||||
# Sync job list every 60 seconds (only adds/removes when services change)
|
||||
scheduler.add_job(sync_jobs, "interval", seconds=60, id="sync_jobs")
|
||||
|
||||
# Prune old checks every 15 minutes (retention/compression)
|
||||
scheduler.add_job(prune_checks_retention, "interval", minutes=15, id="prune_checks")
|
||||
|
||||
scheduler.start()
|
||||
|
||||
@@ -10,4 +10,5 @@ services:
|
||||
- ./data:/app/data
|
||||
environment:
|
||||
- VERSION=${IMAGE_TAG:-latest}
|
||||
# Optional: CHECK_RETENTION_COUNT=5000, CHECK_RETENTION_DAYS=30
|
||||
restart: unless-stopped
|
||||
|
||||
Reference in New Issue
Block a user