support periodically cleaning up expired tokens

This commit is contained in:
MaysWind
2024-08-12 00:49:07 +08:00
parent 80b8b9afdd
commit 52dfee9ca6
22 changed files with 506 additions and 7 deletions
+101
View File
@@ -0,0 +1,101 @@
package cron
import (
"time"
"github.com/go-co-op/gocron/v2"
"github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/log"
"github.com/mayswind/ezbookkeeping/pkg/settings"
)
// CronJobSchedulerContainer contains the current cron job scheduler
type CronJobSchedulerContainer struct {
scheduler gocron.Scheduler
allJobs []*CronJob
allJobsMap map[string]*CronJob
allGocronJobsMap map[string]gocron.Job
}
// Initialize a cron job scheduler container singleton instance
var (
Container = &CronJobSchedulerContainer{
allJobsMap: make(map[string]*CronJob),
allGocronJobsMap: make(map[string]gocron.Job),
}
)
// InitializeCronJobSchedulerContainer initializes the cron job scheduler according to the config
func InitializeCronJobSchedulerContainer(config *settings.Config, startScheduler bool) error {
var err error
Container.scheduler, err = gocron.NewScheduler(
gocron.WithLocation(time.Local),
gocron.WithLogger(NewGocronLoggerAdapter()),
)
if err != nil {
return err
}
Container.registerAllJobs(config)
if startScheduler {
Container.scheduler.Start()
}
return nil
}
// GetAllJobs returns all the cron jobs
func (c *CronJobSchedulerContainer) GetAllJobs() []*CronJob {
return c.allJobs
}
// SyncRunJobNow runs the specified cron job synchronously now
func (c *CronJobSchedulerContainer) SyncRunJobNow(jobName string) error {
if jobName == "" {
return errs.ErrCronJobNameIsEmpty
}
job := c.allJobsMap[jobName]
if job == nil {
return errs.ErrCronJobNotExistsOrNotEnabled
}
gocronJob := c.allGocronJobsMap[jobName]
if gocronJob == nil {
return errs.ErrCronJobNotExistsOrNotEnabled
}
job.doRun()
return nil
}
func (c *CronJobSchedulerContainer) registerAllJobs(config *settings.Config) {
if config.EnableRemoveExpiredTokens {
Container.registerIntervalJob(RemoveExpiredTokensJob)
}
}
func (c *CronJobSchedulerContainer) registerIntervalJob(job *CronJob) {
gocronJob, err := c.scheduler.NewJob(
gocron.DurationJob(job.Interval),
gocron.NewTask(job.doRun),
gocron.WithName(job.Name),
gocron.WithSingletonMode(gocron.LimitModeReschedule),
)
if err == nil {
c.allJobs = append(c.allJobs, job)
c.allJobsMap[job.Name] = job
c.allGocronJobsMap[job.Name] = gocronJob
log.Infof("[cron_container.registerJob] job \"%s\" has been registered", job.Name)
log.Debugf("[cron_container.registerJob] job \"%s\" gocron id is %s", job.Name, gocronJob.ID())
} else {
log.Errorf("[cron_container.registerJob] job \"%s\" cannot be been registered, because %s", job.Name, err.Error())
}
}
+49
View File
@@ -0,0 +1,49 @@
package cron
import (
"fmt"
"time"
"github.com/mayswind/ezbookkeeping/pkg/duplicatechecker"
"github.com/mayswind/ezbookkeeping/pkg/log"
"github.com/mayswind/ezbookkeeping/pkg/utils"
)
type CronJob struct {
Name string
Description string
Interval time.Duration
Run func() error
}
func (c *CronJob) doRun() {
start := time.Now()
localAddr, err := utils.GetLocalIPAddressesString()
if err != nil {
log.Warnf("[cron_job.doRun] job \"%s\" cannot get local ipv4 address, because %s", c.Name, err.Error())
return
}
currentInfo := fmt.Sprintf("ip: %s, startTime: %d", localAddr, time.Now().Unix())
found, runningInfo := duplicatechecker.Container.GetOrSetCronJobRunningInfo(c.Name, currentInfo, c.Interval)
if found {
log.Warnf("[cron_job.doRun] job \"%s\" is already running (%s)", c.Name, runningInfo)
return
}
err = c.Run()
duplicatechecker.Container.Current.RemoveCronJobRunningInfo(c.Name)
now := time.Now()
if err != nil {
log.Errorf("[cron_job.doRun] failed to run job \"%s\", because %s", c.Name, err.Error())
return
}
cost := now.Sub(start).Nanoseconds() / 1e6
log.Infof("[cron_job.doRun] run job \"%s\" successfully, cost %dms", c.Name, cost)
}
+16
View File
@@ -0,0 +1,16 @@
package cron
import (
"time"
"github.com/mayswind/ezbookkeeping/pkg/services"
)
var RemoveExpiredTokensJob = &CronJob{
Name: "RemoveExpiredTokens",
Description: "Periodically remove expired user tokens from the database.",
Interval: 24 * time.Hour,
Run: func() error {
return services.Tokens.DeleteAllExpiredTokens(nil)
},
}
+36
View File
@@ -0,0 +1,36 @@
package cron
import (
"github.com/go-co-op/gocron/v2"
"github.com/mayswind/ezbookkeeping/pkg/log"
)
// GocronLoggerAdapter represents the logger adapter for gocron
type GocronLoggerAdapter struct {
}
// Debug logs debug log
func (logger GocronLoggerAdapter) Debug(msg string, args ...any) {
log.Debugf(msg, args...)
}
// Info logs info log
func (logger GocronLoggerAdapter) Info(msg string, args ...any) {
log.Infof(msg, args...)
}
// Warn logs warn log
func (logger GocronLoggerAdapter) Warn(msg string, args ...any) {
log.Warnf(msg, args...)
}
// Error logs error log
func (logger GocronLoggerAdapter) Error(msg string, args ...any) {
log.Errorf(msg, args...)
}
// NewGocronLoggerAdapter returns a new GocronLoggerAdapter instance
func NewGocronLoggerAdapter() gocron.Logger {
return GocronLoggerAdapter{}
}