From 5a715cc60ad66ab0d9e7737631159ace79615228 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Wed, 21 Feb 2024 19:49:52 +0200 Subject: [PATCH] [#4394] reschedule the first cron tick to start at 00 second --- CHANGELOG.md | 3 +++ tools/cron/cron.go | 43 ++++++++++++++++++++++++++++++------------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a67a3a16..776031b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ oauth2 ``` +- Updated the `cron.Start()` to start the ticker at the `00` second of the cron interval ([#4394](https://github.com/pocketbase/pocketbase/discussions/4394)). + _Note that the cron format has only minute granularity and there is still no guarantee that the sheduled job will be always executed at the `00` second._ + - Upgraded to `aws-sdk-go-v2` and added special handling for GCS to workaround the previous [GCS headers signature issue](https://github.com/pocketbase/pocketbase/issues/2231) that we had with v2. _This should also fix the SVG/JSON zero response when using Cloudflare R2 ([#4287](https://github.com/pocketbase/pocketbase/issues/4287#issuecomment-1925168142), [#2068](https://github.com/pocketbase/pocketbase/discussions/2068), [#2952](https://github.com/pocketbase/pocketbase/discussions/2952))._ _If you are using S3 for uploaded files or backups, please verify that you have a green check in the Admin UI for your S3 configuration (I've tested the new version with GCS, MinIO, Cloudflare R2 and Wasabi)._ diff --git a/tools/cron/cron.go b/tools/cron/cron.go index d3f1d1d0..c9e4f46c 100644 --- a/tools/cron/cron.go +++ b/tools/cron/cron.go @@ -22,12 +22,13 @@ type job struct { // Cron is a crontab-like struct for tasks/jobs scheduling. type Cron struct { - sync.RWMutex + timezone *time.Location + ticker *time.Ticker + startTimer *time.Timer + jobs map[string]*job + interval time.Duration - interval time.Duration - timezone *time.Location - ticker *time.Ticker - jobs map[string]*job + sync.RWMutex } // New create a new Cron struct with default tick interval of 1 minute @@ -132,6 +133,11 @@ func (c *Cron) Stop() { c.Lock() defer c.Unlock() + if c.startTimer != nil { + c.startTimer.Stop() + c.startTimer = nil + } + if c.ticker == nil { return // already stopped } @@ -146,15 +152,26 @@ func (c *Cron) Stop() { func (c *Cron) Start() { c.Stop() - c.Lock() - c.ticker = time.NewTicker(c.interval) - c.Unlock() + // delay the ticker to start at 00 of 1 c.interval duration + now := time.Now() + next := now.Add(c.interval).Truncate(c.interval) + delay := next.Sub(now) - go func() { - for t := range c.ticker.C { - c.runDue(t) - } - }() + c.startTimer = time.AfterFunc(delay, func() { + c.Lock() + c.ticker = time.NewTicker(c.interval) + c.Unlock() + + // run immediately at 00 + c.runDue(time.Now()) + + // run after each tick + go func() { + for t := range c.ticker.C { + c.runDue(t) + } + }() + }) } // HasStarted checks whether the current Cron ticker has been started.