package sql import ( "context" "fmt" "log" "time" "github.com/coreos/dex/storage" ) type gc struct { now func() time.Time conn *conn } func (gc gc) run() error { for _, table := range []string{"auth_request", "auth_code"} { _, err := gc.conn.Exec(`delete from `+table+` where expiry < $1`, gc.now()) if err != nil { return fmt.Errorf("gc %s: %v", table, err) } // TODO(ericchiang): when we have levelled logging print how many rows were gc'd } return nil } type withCancel struct { storage.Storage cancel context.CancelFunc } func (w withCancel) Close() error { w.cancel() return w.Storage.Close() } func withGC(conn *conn, now func() time.Time) storage.Storage { ctx, cancel := context.WithCancel(context.Background()) run := (gc{now, conn}).run go func() { for { select { case <-time.After(time.Second * 30): if err := run(); err != nil { log.Printf("gc failed: %v", err) } case <-ctx.Done(): } } }() return withCancel{conn, cancel} }