2026-07-23 09:49:04 +00:00
|
|
|
/// <reference path="../pb_data/types.d.ts" />
|
|
|
|
|
|
|
|
|
|
// Retention for the client_logs diagnostics (feedback 2 §4). These are for
|
client_logs retention: delete every row past 14 days, not 500 a night
The nightly trimClientLogs cron fetched one page of 500 records older than
14 days and deleted those, while about 1275 rows arrive a day. Measured on
production (read-only) on 2026-09-13: 30213 rows, 14420 of them past the
cutoff, the oldest from 2026-08-19, so the backlog grew by roughly 775 rows
a day and the documented 14-day retention never held.
The job now deletes in batches of 2000 with plain SQL until a batch comes
back short, so one run clears everything past the cutoff. Plain SQL instead
of $app.delete() per record is safe here: client_logs has no file fields, no
collection has a relation pointing at it and no hook watches its deletes, so
the record path would only add a transaction and a cascade lookup per row.
Batches keep each write lock short. The run logs "trimClientLogs" with the
deleted count and the cutoff to PocketBase's logs, and a failure is logged
instead of swallowed silently as before.
scripts/test_client_logs_trim.py starts a throwaway PocketBase 0.39.6 with
this repo's migrations and hooks, seeds stale and fresh rows, fires the job
through POST /api/crons/trimClientLogs and checks what is left. Against the
old hook it failed: 800 of 1300 stale rows left, no log line. With the fix:
0 of 1300 left, all 40 in-window rows kept (one just inside the cutoff), and
0 of 15000 stale rows left in 0.4 s at production scale.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 20:32:34 +00:00
|
|
|
// live debugging, not an archive — delete everything older than 14 days daily
|
|
|
|
|
// so the collection can't grow unbounded. Runs in PocketBase's cron scheduler.
|
|
|
|
|
//
|
|
|
|
|
// Every stale row goes in one run. The first version deleted a single page of
|
|
|
|
|
// 500 records a night while ~1275 rows arrived a day, so on 2026-09-13 about
|
|
|
|
|
// 14400 rows past the cutoff were still there, the oldest from 2026-08-19.
|
|
|
|
|
//
|
|
|
|
|
// Plain SQL rather than $app.delete() per record: client_logs has no file
|
|
|
|
|
// fields, no collection has a relation pointing at it and no hook watches its
|
|
|
|
|
// deletes, so the record path would only add a transaction and a cascade lookup
|
|
|
|
|
// per row. Batches keep each write lock short so app requests are not held up.
|
|
|
|
|
// The run leaves one line in PocketBase's logs (dashboard, /api/logs).
|
2026-07-23 09:49:04 +00:00
|
|
|
cronAdd("trimClientLogs", "0 4 * * *", () => {
|
client_logs retention: delete every row past 14 days, not 500 a night
The nightly trimClientLogs cron fetched one page of 500 records older than
14 days and deleted those, while about 1275 rows arrive a day. Measured on
production (read-only) on 2026-09-13: 30213 rows, 14420 of them past the
cutoff, the oldest from 2026-08-19, so the backlog grew by roughly 775 rows
a day and the documented 14-day retention never held.
The job now deletes in batches of 2000 with plain SQL until a batch comes
back short, so one run clears everything past the cutoff. Plain SQL instead
of $app.delete() per record is safe here: client_logs has no file fields, no
collection has a relation pointing at it and no hook watches its deletes, so
the record path would only add a transaction and a cascade lookup per row.
Batches keep each write lock short. The run logs "trimClientLogs" with the
deleted count and the cutoff to PocketBase's logs, and a failure is logged
instead of swallowed silently as before.
scripts/test_client_logs_trim.py starts a throwaway PocketBase 0.39.6 with
this repo's migrations and hooks, seeds stale and fresh rows, fires the job
through POST /api/crons/trimClientLogs and checks what is left. Against the
old hook it failed: 800 of 1300 stale rows left, no log line. With the fix:
0 of 1300 left, all 40 in-window rows kept (one just inside the cutoff), and
0 of 15000 stale rows left in 0.4 s at production scale.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 20:32:34 +00:00
|
|
|
const BATCH = 2000
|
|
|
|
|
const cutoff = new Date(Date.now() - 14 * 24 * 60 * 60 * 1000)
|
|
|
|
|
.toISOString().replace("T", " ").slice(0, 19) + ".000Z"
|
|
|
|
|
let deleted = 0
|
2026-07-23 09:49:04 +00:00
|
|
|
try {
|
client_logs retention: delete every row past 14 days, not 500 a night
The nightly trimClientLogs cron fetched one page of 500 records older than
14 days and deleted those, while about 1275 rows arrive a day. Measured on
production (read-only) on 2026-09-13: 30213 rows, 14420 of them past the
cutoff, the oldest from 2026-08-19, so the backlog grew by roughly 775 rows
a day and the documented 14-day retention never held.
The job now deletes in batches of 2000 with plain SQL until a batch comes
back short, so one run clears everything past the cutoff. Plain SQL instead
of $app.delete() per record is safe here: client_logs has no file fields, no
collection has a relation pointing at it and no hook watches its deletes, so
the record path would only add a transaction and a cascade lookup per row.
Batches keep each write lock short. The run logs "trimClientLogs" with the
deleted count and the cutoff to PocketBase's logs, and a failure is logged
instead of swallowed silently as before.
scripts/test_client_logs_trim.py starts a throwaway PocketBase 0.39.6 with
this repo's migrations and hooks, seeds stale and fresh rows, fires the job
through POST /api/crons/trimClientLogs and checks what is left. Against the
old hook it failed: 800 of 1300 stale rows left, no log line. With the fix:
0 of 1300 left, all 40 in-window rows kept (one just inside the cutoff), and
0 of 15000 stale rows left in 0.4 s at production scale.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 20:32:34 +00:00
|
|
|
for (;;) {
|
|
|
|
|
const n = $app.db().newQuery(
|
|
|
|
|
"DELETE FROM client_logs WHERE id IN " +
|
|
|
|
|
"(SELECT id FROM client_logs WHERE created < {:c} LIMIT {:n})"
|
|
|
|
|
).bind({ c: cutoff, n: BATCH }).execute().rowsAffected()
|
|
|
|
|
deleted += n
|
|
|
|
|
if (n < BATCH) break
|
|
|
|
|
}
|
|
|
|
|
$app.logger().info("trimClientLogs", "deleted", deleted, "cutoff", cutoff)
|
|
|
|
|
} catch (e) {
|
|
|
|
|
$app.logger().error("trimClientLogs failed",
|
|
|
|
|
"error", String(e), "deleted", deleted, "cutoff", cutoff)
|
|
|
|
|
}
|
2026-07-23 09:49:04 +00:00
|
|
|
})
|