From 4ef9e19fbcea233411fd33598ca548a6eddb7cc7 Mon Sep 17 00:00:00 2001 From: mstar Date: Fri, 4 Apr 2025 16:16:08 +0200 Subject: [PATCH] Add cleaner services Initial cleaner is for expiring access tokens --- storage-new/cleaners/ExpireAccessTokens.go | 19 ++++++ storage-new/cleaners/manager.go | 70 ++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 storage-new/cleaners/ExpireAccessTokens.go create mode 100644 storage-new/cleaners/manager.go diff --git a/storage-new/cleaners/ExpireAccessTokens.go b/storage-new/cleaners/ExpireAccessTokens.go new file mode 100644 index 0000000..780b109 --- /dev/null +++ b/storage-new/cleaners/ExpireAccessTokens.go @@ -0,0 +1,19 @@ +package cleaners + +import ( + "time" + + "git.mstar.dev/mstar/linstrom/storage-new/dbgen" +) + +func init() { + cleanerBuilders = append(cleanerBuilders, buildExpireAccessTokens) +} + +func tickExpireAccessTokens(now time.Time) { + dbgen.AccessToken.Where(dbgen.AccessToken.ExpiresAt.Lt(time.Now())).Delete() +} + +func buildExpireAccessTokens() (onTick func(time.Time), name string, tickSpeed time.Duration) { + return tickExpireAccessTokens, "expire-access-tokens", time.Hour +} diff --git a/storage-new/cleaners/manager.go b/storage-new/cleaners/manager.go new file mode 100644 index 0000000..fcb3ccf --- /dev/null +++ b/storage-new/cleaners/manager.go @@ -0,0 +1,70 @@ +package cleaners + +import ( + "sync" + "time" +) + +type CleanerManager struct { + activeCleaners map[string]bool + activeCleanerLock sync.Mutex + exitChans []chan any +} + +var cleanerBuilders = []func() (onTick func(time.Time), name string, tickSpeed time.Duration){} + +func NewManager() *CleanerManager { + activeCleaners := make(map[string]bool) + exitChans := []chan any{} + cm := &CleanerManager{ + activeCleaners: activeCleaners, + exitChans: exitChans, + } + + // Launch all cleaner tickers in a new goroutine each + for _, builder := range cleanerBuilders { + exitChan := make(chan any, 1) + onTick, name, tickSpeed := builder() + cm.exitChans = append(cm.exitChans, exitChan) + go cm.tickOrExit(tickSpeed, name, exitChan, onTick) + } + + return cm +} + +func (m *CleanerManager) Stop() { + for _, exitChan := range m.exitChans { + exitChan <- 1 + } +} + +func (m *CleanerManager) tickOrExit( + tickSpeed time.Duration, + name string, + exitChan chan any, + onTick func(time.Time), +) { + ticker := time.Tick(tickSpeed) + for { + select { + case now := <-ticker: + go m.wrapOnTick(name, now, onTick) + case <-exitChan: + return + } + } +} + +func (m *CleanerManager) wrapOnTick(name string, now time.Time, onTick func(time.Time)) { + m.activeCleanerLock.Lock() + if m.activeCleaners[name] { + m.activeCleanerLock.Unlock() + return + } + m.activeCleaners[name] = true + m.activeCleanerLock.Unlock() + onTick(now) + m.activeCleanerLock.Lock() + m.activeCleaners[name] = false + m.activeCleanerLock.Unlock() +}