Add a cron to delete expired sessions

This commit is contained in:
Ben Visness 2021-03-27 23:22:29 -05:00
parent 608d1af195
commit 8f2958594a
2 changed files with 57 additions and 0 deletions

View File

@ -11,6 +11,7 @@ import (
"git.handmade.network/hmn/hmn/src/config" "git.handmade.network/hmn/hmn/src/config"
"git.handmade.network/hmn/hmn/src/db" "git.handmade.network/hmn/hmn/src/db"
"git.handmade.network/hmn/hmn/src/logging"
"git.handmade.network/hmn/hmn/src/models" "git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/oops" "git.handmade.network/hmn/hmn/src/oops"
"github.com/jackc/pgx/v4/pgxpool" "github.com/jackc/pgx/v4/pgxpool"
@ -94,3 +95,39 @@ var DeleteSessionCookie = &http.Cookie{
Domain: config.Config.Auth.CookieDomain, Domain: config.Config.Auth.CookieDomain,
MaxAge: -1, MaxAge: -1,
} }
func DeleteExpiredSessions(ctx context.Context, conn *pgxpool.Pool) (int64, error) {
tag, err := conn.Exec(ctx, "DELETE FROM sessions WHERE expires_at <= CURRENT_TIMESTAMP")
if err != nil {
return 0, oops.New(err, "failed to delete expired sessions")
}
return tag.RowsAffected(), nil
}
func PeriodicallyDeleteExpiredSessions(ctx context.Context, conn *pgxpool.Pool) <-chan struct{} {
done := make(chan struct{})
go func() {
defer close(done)
t := time.NewTicker(1 * time.Minute)
for {
select {
case <-t.C:
n, err := DeleteExpiredSessions(ctx, conn)
if err == nil {
if n > 0 {
logging.Info().Int64("num deleted sessions", n).Msg("Deleted expired sessions")
} else {
logging.Debug().Msg("no sessions to delete")
}
} else {
logging.Error().Err(err).Msg("Failed to delete expired sessions")
}
case <-ctx.Done():
return
}
}
}()
return done
}

View File

@ -8,6 +8,7 @@ import (
"os/signal" "os/signal"
"time" "time"
"git.handmade.network/hmn/hmn/src/auth"
"git.handmade.network/hmn/hmn/src/config" "git.handmade.network/hmn/hmn/src/config"
"git.handmade.network/hmn/hmn/src/db" "git.handmade.network/hmn/hmn/src/db"
"git.handmade.network/hmn/hmn/src/logging" "git.handmade.network/hmn/hmn/src/logging"
@ -31,6 +32,11 @@ var WebsiteCommand = &cobra.Command{
Handler: NewWebsiteRoutes(conn), Handler: NewWebsiteRoutes(conn),
} }
backgroundJobContext, cancelBackgroundJobs := context.WithCancel(context.Background())
backgroundJobsDone := zipJobs(
auth.PeriodicallyDeleteExpiredSessions(backgroundJobContext, conn),
)
signals := make(chan os.Signal, 1) signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt) signal.Notify(signals, os.Interrupt)
go func() { go func() {
@ -39,6 +45,7 @@ var WebsiteCommand = &cobra.Command{
timeout, cancel := context.WithTimeout(context.Background(), 30*time.Second) timeout, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() defer cancel()
server.Shutdown(timeout) server.Shutdown(timeout)
cancelBackgroundJobs()
<-signals <-signals
logging.Warn().Msg("Forcibly killed the website") logging.Warn().Msg("Forcibly killed the website")
@ -50,5 +57,18 @@ var WebsiteCommand = &cobra.Command{
if !errors.Is(serverErr, http.ErrServerClosed) { if !errors.Is(serverErr, http.ErrServerClosed) {
logging.Error().Err(serverErr).Msg("Server shut down unexpectedly") logging.Error().Err(serverErr).Msg("Server shut down unexpectedly")
} }
<-backgroundJobsDone
}, },
} }
func zipJobs(cs ...<-chan struct{}) <-chan struct{} {
out := make(chan struct{})
go func() {
for _, c := range cs {
<-c
}
close(out)
}()
return out
}