From 0a30a7cab39d99138ae405530ea9549940bc083e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Matczuk?= Date: Tue, 21 Dec 2021 13:59:47 +0100 Subject: [PATCH] service/scheduler: add Cron type --- .golangci.yml | 1 + pkg/service/scheduler/cron.go | 76 ++++++++++++++++++++++++++++++ pkg/service/scheduler/cron_test.go | 28 +++++++++++ 3 files changed, 105 insertions(+) create mode 100644 pkg/service/scheduler/cron.go create mode 100644 pkg/service/scheduler/cron_test.go diff --git a/.golangci.yml b/.golangci.yml index d385601e37..d5a166b276 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -79,6 +79,7 @@ issues: - exported method +\.Close should have comment or be unexported - exported method .*Value\..+ should have comment or be unexported - exported method .+\.Init should have comment or be unexported + - exported method .+\.IsZero should have comment or be unexported - exported method .+\.Key should have comment or be unexported - exported method .+\.MarshalBinary should have comment or be unexported - exported method .+\.MarshalCQL should have comment or be unexported diff --git a/pkg/service/scheduler/cron.go b/pkg/service/scheduler/cron.go new file mode 100644 index 0000000000..d70224ee43 --- /dev/null +++ b/pkg/service/scheduler/cron.go @@ -0,0 +1,76 @@ +// Copyright (C) 2017 ScyllaDB + +package scheduler + +import ( + "time" + + "github.com/gocql/gocql" + "github.com/pkg/errors" + "github.com/scylladb/scylla-manager/pkg/scheduler" + "github.com/scylladb/scylla-manager/pkg/scheduler/trigger" +) + +// Cron implements a trigger based on cron expression. +// It supports the extended syntax including @monthly, @weekly, @daily, @midnight, @hourly, @every . +type Cron struct { + spec []byte + inner scheduler.Trigger +} + +func NewCron(spec string) (Cron, error) { + t, err := trigger.NewCron(spec) + if err != nil { + return Cron{}, err + } + + return Cron{ + spec: []byte(spec), + inner: t, + }, nil +} + +func NewCronEvery(d time.Duration) Cron { + c, _ := NewCron("@every " + d.String()) // nolint: errcheck + return c +} + +// MustCron calls NewCron and panics on error. +func MustCron(spec string) Cron { + c, err := NewCron(spec) + if err != nil { + panic(err) + } + return c +} + +// Next implements scheduler.Trigger. +func (c Cron) Next(now time.Time) time.Time { + return c.inner.Next(now) +} + +func (c Cron) MarshalText() (text []byte, err error) { + return c.spec, nil +} + +func (c *Cron) UnmarshalText(text []byte) error { + v, err := NewCron(string(text)) + if err != nil { + return errors.Wrap(err, "cron") + } + + *c = v + return nil +} + +func (c Cron) MarshalCQL(info gocql.TypeInfo) ([]byte, error) { + return c.MarshalText() +} + +func (c *Cron) UnmarshalCQL(info gocql.TypeInfo, data []byte) error { + return c.UnmarshalText(data) +} + +func (c Cron) IsZero() bool { + return c.inner == nil +} diff --git a/pkg/service/scheduler/cron_test.go b/pkg/service/scheduler/cron_test.go new file mode 100644 index 0000000000..81f30b360d --- /dev/null +++ b/pkg/service/scheduler/cron_test.go @@ -0,0 +1,28 @@ +// Copyright (C) 2021 ScyllaDB + +package scheduler + +import ( + "testing" + "time" +) + +func TestCronMarshalUnmarshal(t *testing.T) { + spec := "@every 15s" + + var cron Cron + if err := cron.UnmarshalText([]byte(spec)); err != nil { + t.Fatal(err) + } + b, _ := cron.MarshalText() + if string(b) != spec { + t.Fatalf("MarshalText() = %s, expected %s", string(b), spec) + } +} + +func TestNewCronEvery(t *testing.T) { + c := NewCronEvery(15 * time.Second) + if c.IsZero() { + t.Fatal() + } +}