From b9b0e43854bb4b4530838ee96685ba7ba3cea09b Mon Sep 17 00:00:00 2001 From: Victor Castell Date: Thu, 2 Jun 2016 23:15:20 +0200 Subject: [PATCH] One off jobs (#137) One off jobs --- .travis.yml | 6 +----- cron/doc.go | 13 +++++++++++++ cron/parser.go | 9 +++++++++ cron/parser_test.go | 2 ++ cron/simple.go | 21 +++++++++++++++++++++ scripts/test.sh | 2 +- 6 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 cron/simple.go diff --git a/.travis.yml b/.travis.yml index 56f0189dd..eab6e8dcd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,8 +23,4 @@ script: - go vet ./... # - fgt golint ./... - glide install - - go test -v ./dkron - -env: - global: - - GO15VENDOREXPERIMENT=1 + - go test -v $(glide novendor) diff --git a/cron/doc.go b/cron/doc.go index be39098ce..5aba99cdc 100644 --- a/cron/doc.go +++ b/cron/doc.go @@ -100,6 +100,19 @@ Note: The interval does not take the job runtime into account. For example, if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes, it will have only 2 minutes of idle time between each run. +Fixed times + +You may also schedule a job to execute once and never more. This is supported by +formatting the cron spec like this: + + @at + +Where "datetime" is a string accepted by time.Parse in RFC 3339/ISO 8601 format +(https://golang.org/pkg/time/#Parse). + +For example, "@at 2018-01-02T15:04:00" would run the job on the specified date and time +assuming UTC timezone. + Time zones All interpretation and scheduling is done in the machine's local time zone (as diff --git a/cron/parser.go b/cron/parser.go index fd04dca82..e4342d306 100644 --- a/cron/parser.go +++ b/cron/parser.go @@ -236,6 +236,15 @@ func parseDescriptor(spec string) Schedule { return Every(duration) } + const at = "@at " + if strings.HasPrefix(spec, at) { + date, err := time.Parse(time.RFC3339, spec[len(at):]) + if err != nil { + log.Panicf("Failed to parse date %s: %s", spec, err) + } + return At(date) + } + log.Panicf("Unrecognized descriptor: %s", spec) return nil } diff --git a/cron/parser_test.go b/cron/parser_test.go index f03299e5e..db76cb2e1 100644 --- a/cron/parser_test.go +++ b/cron/parser_test.go @@ -103,6 +103,8 @@ func TestSpecSchedule(t *testing.T) { }{ {"* 5 * * * *", &SpecSchedule{all(seconds), 1 << 5, all(hours), all(dom), all(months), all(dow)}}, {"@every 5m", ConstantDelaySchedule{time.Duration(5) * time.Minute}}, + {"@at 2018-01-02T15:04:00Z", SimpleSchedule{time.Date(2018, time.January, 2, 15, 4, 0, 0, time.UTC)}}, + {"@at 2019-02-04T09:20:00+06:00", SimpleSchedule{time.Date(2019, time.February, 4, 9, 20, 0, 0, time.FixedZone("", 21600))}}, } for _, c := range entries { diff --git a/cron/simple.go b/cron/simple.go new file mode 100644 index 000000000..445374bde --- /dev/null +++ b/cron/simple.go @@ -0,0 +1,21 @@ +package cron + +import "time" + +// SimpleDelaySchedule represents a simple non recurring duration. +type SimpleSchedule struct { + Date time.Time +} + +// Just store the given time for this schedule. +func At(date time.Time) SimpleSchedule { + return SimpleSchedule{ + Date: date, + } +} + +// Next conforms to the Schedule interface but this kind of jobs +// doesn't need to be run more than once, so it doesn't return a new date but the existing one. +func (schedule SimpleSchedule) Next(t time.Time) time.Time { + return schedule.Date +} diff --git a/scripts/test.sh b/scripts/test.sh index 43f3a706c..ee99e210c 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -3,4 +3,4 @@ docker-compose up -d etcd export COMPOSE_ETCD_PORT=`docker port dkron_etcd_1 4001/tcp | cut -d":" -f 2` export DKRON_BACKEND_MACHINE=`docker-machine ip default`:$COMPOSE_ETCD_PORT -go test -v ./dkron $1 +go test -v $(glide novendor) $1