Add webhook-event retention job, schema, and testdb pre-flight hint

square_webhook_events is now CREATE TABLE IF NOT EXISTS, registered as the 24th maintenance job (sweep-square-webhook-events, daily 2:30am) pruning rows older than 90 days, and testdb gives a clear docker compose hint when the admin DB connection fails.
This commit is contained in:
2026-08-22 00:34:49 +01:00
parent 5ea89da2ad
commit 8720e28dbe
5 changed files with 155 additions and 2 deletions
+44
View File
@@ -1,14 +1,21 @@
package jobs
import (
"context"
"errors"
"fmt"
"log/slog"
"time"
"crussell/auth"
"crussell/db"
authHandlers "crussell/handlers/auth"
"crussell/handlers/payments"
"crussell/handlers/scheduling"
"crussell/handlers/user"
"crussell/mw"
"github.com/jackc/pgx/v5"
)
// RegisterAll registers every background maintenance job on the scheduler.
@@ -214,4 +221,41 @@ func RegisterAll(s *Scheduler) {
Concurrency: 1,
Handler: scheduling.CleanupExpiredRefreshTokens,
})
// Staggered from cleanup-verification-codes / cleanup-refresh-tokens
// (both at 0 2 * * *) to avoid DB contention.
s.Register(Job{
Name: "sweep-square-webhook-events",
Schedule: "30 2 * * *", // Daily at 2:30am
Timeout: 30 * time.Second,
Concurrency: 1,
Handler: SweepSquareWebhookEvents,
})
}
// SweepSquareWebhookEvents deletes square_webhook_events rows older than 90
// days. Every accepted webhook event_id is stored permanently for restart-safe
// dedup (payment.updated fires on every payment update), so without retention
// the table would grow without bound. 90 days comfortably exceeds Square's
// webhook replay window while keeping the table bounded.
func SweepSquareWebhookEvents(ctx context.Context) (int, error) {
tx, err := db.Conn.Begin(ctx)
if err != nil {
return 0, fmt.Errorf("failed to begin transaction: %w", err)
}
defer func() {
if err := tx.Rollback(ctx); err != nil && !errors.Is(err, pgx.ErrTxClosed) {
slog.Error("failed to rollback transaction", "err", err)
}
}()
tag, err := tx.Exec(ctx, `
DELETE FROM square_webhook_events
WHERE received_at < NOW() - INTERVAL '90 days'
`)
if err != nil {
return 0, fmt.Errorf("failed to sweep square webhook events: %w", err)
}
return int(tag.RowsAffected()), tx.Commit(ctx)
}