diff --git a/engine/collector_cache.go b/engine/collector_cache.go new file mode 100644 index 00000000..0108deb6 --- /dev/null +++ b/engine/collector_cache.go @@ -0,0 +1,72 @@ +package engine + +import ( + "context" + "log" + "time" + + "github.com/Masterminds/squirrel" + "github.com/loopfz/gadgeto/zesty" + "github.com/ovh/utask" + "github.com/ovh/utask/db/pgjuju" + "github.com/ovh/utask/db/sqlgenerator" + "github.com/ovh/utask/pkg/now" +) + +// CacheCollector launches a process that cleans up expired entries from the cache plugin +func CacheCollector(ctx context.Context) error { + dbp, err := zesty.NewDBProvider(utask.DBName) + if err != nil { + return err + } + + // Using the same duration as the GarbageCollector + sleepDuration := sleepDurationDefault + + // Delete expired entries from the cache plugin + go func() { + // Run it immediately and wait for new tick + if purged, err := purgeExpiredEntries(dbp); err != nil { + log.Printf("CacheCollector: failed to trash expired entries: %s", err) + } else if purged > 0 { + log.Printf("CacheCollector: purged %d expired entries at startup", purged) + } + + for running := true; running; { + time.Sleep(sleepDuration) + + select { + case <-ctx.Done(): + running = false + default: + if purged, err := purgeExpiredEntries(dbp); err != nil { + log.Printf("CacheCollector: failed to trash expired entries: %s", err) + } else if purged > 0 { + log.Printf("CacheCollector: purged %d expired entries", purged) + } + } + } + }() + + return nil +} + +func purgeExpiredEntries(dbp zesty.DBProvider) (int64, error) { + query, args, err := sqlgenerator.PGsql. + Delete(`"cache"`). + Where(squirrel.And{ + squirrel.NotEq{`"expires_at"`: nil}, + squirrel.Lt{`"expires_at"`: now.Get()}, + }). + ToSql() + if err != nil { + return 0, err + } + + res, err := dbp.DB().Exec(query, args...) + if err != nil { + return 0, pgjuju.Interpret(err) + } + + return res.RowsAffected() +} diff --git a/engine/engine.go b/engine/engine.go index 243ad3e4..d923ae57 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -136,6 +136,10 @@ func Init(ctx context.Context, wg *sync.WaitGroup, store *configstore.Store) err if err := GarbageCollector(ctx, cfg.CompletedTaskExpiration); err != nil { return err } + // init cache collector (delete expired entries from the cache plugin) + if err := CacheCollector(ctx); err != nil { + return err + } // init autorun collector (create resolution + run for tasks with state == autorun) if err := AutorunCollector(ctx); err != nil { return err diff --git a/pkg/plugins/builtin/builtin.go b/pkg/plugins/builtin/builtin.go index 27e3ea31..3e4f3e1b 100644 --- a/pkg/plugins/builtin/builtin.go +++ b/pkg/plugins/builtin/builtin.go @@ -23,7 +23,6 @@ import ( func RegisterInit(service *plugins.Service) error { for pluginName, pluginSymbol := range map[string]plugins.InitializerPlugin{ "callback": plugincallback.Init, - "cache": plugincache.Init, } { if err := plugins.RegisterInit(pluginName, pluginSymbol, service); err != nil { return err diff --git a/pkg/plugins/builtin/cache/init.go b/pkg/plugins/builtin/cache/init.go deleted file mode 100644 index 47b73397..00000000 --- a/pkg/plugins/builtin/cache/init.go +++ /dev/null @@ -1,41 +0,0 @@ -package plugincache - -import ( - "github.com/loopfz/gadgeto/zesty" - "github.com/ovh/utask" - "github.com/ovh/utask/pkg/plugins" - "github.com/sirupsen/logrus" -) - -var ( - Init = &CacheInit{} -) - -// CacheInit handles the plugin initialization: table registration -// and periodic cleanup of expired entries. -type CacheInit struct{} - -func (ci *CacheInit) Init(s *plugins.Service) error { - // No table model registration needed: we use raw SQL queries - // with squirrel, not gorp ORM mapping. - - // Purge expired entries at startup - dbp, err := zesty.NewDBProvider(utask.DBName) - if err != nil { - logrus.Warnf("cache plugin: unable to get DB provider for initial purge: %s", err) - return nil - } - - purged, err := purgeExpiredEntries(dbp) - if err != nil { - logrus.Warnf("cache plugin: initial purge failed: %s", err) - } else if purged > 0 { - logrus.Infof("cache plugin: purged %d expired entries at startup", purged) - } - - return nil -} - -func (ci *CacheInit) Description() string { - return "Cache plugin: key-value store with optional TTL expiration" -} diff --git a/pkg/plugins/builtin/cache/models.go b/pkg/plugins/builtin/cache/models.go index 03713e67..75ac7a92 100644 --- a/pkg/plugins/builtin/cache/models.go +++ b/pkg/plugins/builtin/cache/models.go @@ -91,23 +91,3 @@ func deleteCacheEntry(dbp zesty.DBProvider, key string) error { return nil } - -func purgeExpiredEntries(dbp zesty.DBProvider) (int64, error) { - query, args, err := sqlgenerator.PGsql. - Delete(`"cache"`). - Where(squirrel.And{ - squirrel.NotEq{`"expires_at"`: nil}, - squirrel.Lt{`"expires_at"`: now.Get()}, - }). - ToSql() - if err != nil { - return 0, err - } - - res, err := dbp.DB().Exec(query, args...) - if err != nil { - return 0, pgjuju.Interpret(err) - } - - return res.RowsAffected() -}