carlos / contra Public

Clone
git clone https://amadan.net/carlos/contra

Plain git — no account needed to clone.

Download

Download this file

1package contra
2
3import (
4 "context"
5 "log/slog"
6 "time"
7
8 "github.com/carlosframework/rastrillo/db"
9
10 "github.com/carlosframework/contra/internal/contra/auth"
11 "github.com/carlosframework/contra/internal/contra/store"
12)
13
14// SweepInterval is how often the expired-row sweep runs. Nothing depends on
15// it being prompt: every query already carries its own expiry, so a row that
16// outlives its deadline is inert until this deletes it.
17const SweepInterval = 5 * time.Minute
18
19// Sweep deletes rows whose deadline has passed: half-finished signups and
20// device handoffs nobody completed.
21//
22// Both tables are correct without it — the expiry is in every WHERE clause —
23// so this is not about correctness. It is that an unswept table becomes a log
24// of who tried to sign up and when, and of when each account enrolled a
25// device, which is residue we have no reason to keep. slopbox, whose link
26// shape this follows, has no sweeper and its rows accumulate forever.
27func Sweep(ctx context.Context, d *db.DB, logger *slog.Logger) {
28 signups, err := auth.SweepSignupsIn(ctx, d.G, time.Now().UTC())
29 if err != nil {
30 logger.Warn("sweep signups", "err", err)
31 }
32 links, err := store.New(d.G).SweepLinks(ctx, time.Now().UTC())
33 if err != nil {
34 logger.Warn("sweep device links", "err", err)
35 }
36 if signups > 0 || links > 0 {
37 logger.Info("swept", "signups", signups, "device_links", links)
38 }
39}
40
41// SweepLoop runs Sweep until the context is cancelled. main starts it; App
42// does not, so a test gets a server with no background goroutine and no
43// clock of its own.
44func SweepLoop(ctx context.Context, d *db.DB, logger *slog.Logger) {
45 t := time.NewTicker(SweepInterval)
46 defer t.Stop()
47 Sweep(ctx, d, logger)
48 for {
49 select {
50 case <-ctx.Done():
51 return
52 case <-t.C:
53 Sweep(ctx, d, logger)
54 }
55 }
56}
57