startWALCheckpointer runs PRAGMA wal_checkpoint(TRUNCATE) on a timer so the WAL file can't grow without bound. SQLite's automatic wal_autocheckpoint is PASSIVE: it can only checkpoint frames no reader still needs and never truncates the file. Pad's web UI keeps a steady stream of pollers (dashboard/
()
| 190 | // checkpoint (readers active) just retries next tick. SQLite-only — |
| 191 | // Close() stops it; the Postgres constructor never calls this. |
| 192 | func (s *Store) startWALCheckpointer() { |
| 193 | s.stopMaint = make(chan struct{}) |
| 194 | s.maintDone = make(chan struct{}) |
| 195 | go func() { |
| 196 | defer close(s.maintDone) |
| 197 | ticker := time.NewTicker(walCheckpointInterval) |
| 198 | defer ticker.Stop() |
| 199 | for { |
| 200 | select { |
| 201 | case <-s.stopMaint: |
| 202 | return |
| 203 | case <-ticker.C: |
| 204 | if _, err := s.db.Exec("PRAGMA wal_checkpoint(TRUNCATE)"); err != nil { |
| 205 | slog.Warn("wal checkpoint failed", "error", err) |
| 206 | } |
| 207 | } |
| 208 | } |
| 209 | }() |
| 210 | } |
| 211 | |
| 212 | // openPostgresDB opens and configures a PostgreSQL connection pool. |
| 213 | func openPostgresDB(connStr string) (*sql.DB, error) { |