From ce0385ea754eb6fffff1feb27d44c28f20574735 Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Mon, 26 Jun 2023 07:56:02 -0500 Subject: [PATCH 01/14] fix(schedules): ignore trigger for first time schedule --- cmd/vela-server/schedule.go | 42 ++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index ab0a56b90..89689baa2 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -52,35 +52,29 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met // create a variable to track if a build should be triggered based off the schedule trigger := false - // check if a build has already been triggered for the schedule - if schedule.GetScheduledAt() == 0 { - // trigger a build for the schedule since one has not already been scheduled - trigger = true - } else { - // parse the previous occurrence of the entry for the schedule - prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + // parse the previous occurrence of the entry for the schedule + prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) - continue - } + continue + } - // parse the next occurrence of the entry for the schedule - nextTime, err := gronx.NextTick(schedule.GetEntry(), true) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + // parse the next occurrence of the entry for the schedule + nextTime, err := gronx.NextTick(schedule.GetEntry(), true) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) - continue - } + continue + } - // parse the UNIX timestamp from when the last build was triggered for the schedule - t := time.Unix(schedule.GetScheduledAt(), 0).UTC() + // parse the UNIX timestamp from when the last build was triggered for the schedule + t := time.Unix(schedule.GetScheduledAt(), 0).UTC() - // check if the time since the last triggered build is greater than the entry duration for the schedule - if time.Since(t) > nextTime.Sub(prevTime) { - // trigger a build for the schedule since it has not previously ran - trigger = true - } + // check if the time since the last triggered build is greater than the entry duration for the schedule + if time.Since(t) > nextTime.Sub(prevTime) { + // trigger a build for the schedule since it has not previously ran + trigger = true } if trigger && schedule.GetActive() { From 6c7dac6b36aaada0d9c090bb4c9992022c9249fa Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Mon, 26 Jun 2023 08:00:47 -0500 Subject: [PATCH 02/14] fix(schedules): determine trigger off current UTC time --- cmd/vela-server/schedule.go | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 89689baa2..556dc284f 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -49,34 +49,16 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met continue } - // create a variable to track if a build should be triggered based off the schedule - trigger := false + gron := gronx.New() - // parse the previous occurrence of the entry for the schedule - prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) + // determine if a build should be triggered based off the schedule + trigger, err := gron.IsDue(schedule.GetEntry(), time.Now().UTC()) if err != nil { logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) continue } - // parse the next occurrence of the entry for the schedule - nextTime, err := gronx.NextTick(schedule.GetEntry(), true) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) - - continue - } - - // parse the UNIX timestamp from when the last build was triggered for the schedule - t := time.Unix(schedule.GetScheduledAt(), 0).UTC() - - // check if the time since the last triggered build is greater than the entry duration for the schedule - if time.Since(t) > nextTime.Sub(prevTime) { - // trigger a build for the schedule since it has not previously ran - trigger = true - } - if trigger && schedule.GetActive() { err = processSchedule(schedule, compiler, database, metadata, queue, scm) if err != nil { From ef3010c1e488018173be3078fbb29884cb84e783 Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Mon, 26 Jun 2023 08:17:14 -0500 Subject: [PATCH 03/14] chore: save work --- cmd/vela-server/schedule.go | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 556dc284f..620c8c49f 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -37,6 +37,23 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met // iterate through the list of active schedules for _, s := range schedules { + gron := gronx.New() + + // determine if a build should be triggered based off the schedule + due, err := gron.IsDue(s.GetEntry(), time.Now().UTC()) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, s.GetName()) + + continue + } + + // check if the schedule is due to trigger a build + if !due { + logrus.Tracef("waiting to schedule build for %s", s.GetName()) + + continue + } + // send API call to capture the schedule // // This is needed to ensure we are not dealing with a stale schedule since we fetch @@ -49,17 +66,27 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met continue } - gron := gronx.New() + // parse the previous occurrence of the entry for the schedule + prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) - // determine if a build should be triggered based off the schedule - trigger, err := gron.IsDue(schedule.GetEntry(), time.Now().UTC()) + continue + } + + // parse the next occurrence of the entry for the schedule + nextTime, err := gronx.NextTick(schedule.GetEntry(), true) if err != nil { logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) continue } - if trigger && schedule.GetActive() { + // parse the UNIX timestamp from when the last build was triggered for the schedule + t := time.Unix(schedule.GetScheduledAt(), 0).UTC() + + // check if the time since the last triggered build is greater than the entry duration for the schedule + if time.Since(t) > nextTime.Sub(prevTime) && schedule.GetActive() { err = processSchedule(schedule, compiler, database, metadata, queue, scm) if err != nil { logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) From 05f8ca3a5832327f38ecc40b3fc44c5f0d218af3 Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Mon, 26 Jun 2023 14:37:56 -0500 Subject: [PATCH 04/14] cleanup: ignore inactive schedules --- cmd/vela-server/schedule.go | 49 ++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 620c8c49f..309360177 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -39,7 +39,7 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met for _, s := range schedules { gron := gronx.New() - // determine if a build should be triggered based off the schedule + // check if the schedule is due based off the entry accounting for UTC due, err := gron.IsDue(s.GetEntry(), time.Now().UTC()) if err != nil { logrus.WithError(err).Warnf("%s for %s", baseErr, s.GetName()) @@ -66,33 +66,48 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met continue } - // parse the previous occurrence of the entry for the schedule - prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + // ignore triggering a build if the schedule is no longer active + if !schedule.GetActive() { + logrus.Tracef("ignoring to schedule build for %s", s.GetName()) continue } - // parse the next occurrence of the entry for the schedule - nextTime, err := gronx.NextTick(schedule.GetEntry(), true) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) - - continue - } + // check if a build has already been triggered for the schedule + if schedule.GetScheduledAt() > 0 { + // parse the previous occurrence of the entry for the schedule + prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) - // parse the UNIX timestamp from when the last build was triggered for the schedule - t := time.Unix(schedule.GetScheduledAt(), 0).UTC() + continue + } - // check if the time since the last triggered build is greater than the entry duration for the schedule - if time.Since(t) > nextTime.Sub(prevTime) && schedule.GetActive() { - err = processSchedule(schedule, compiler, database, metadata, queue, scm) + // parse the next occurrence of the entry for the schedule + nextTime, err := gronx.NextTick(schedule.GetEntry(), true) if err != nil { logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) continue } + + // parse the UNIX timestamp from when the last build was triggered for the schedule + t := time.Unix(schedule.GetScheduledAt(), 0).UTC() + + // check if the time since the last triggered build is less than the entry duration for the schedule + if time.Since(t) < nextTime.Sub(prevTime) { + logrus.Tracef("waiting to schedule build for %s", s.GetName()) + + continue + } + } + + // process the schedule and trigger a new build + err = processSchedule(schedule, compiler, database, metadata, queue, scm) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + + continue } } From d0024636ea442df2723ab098004c410491d06dcf Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Mon, 26 Jun 2023 14:54:37 -0500 Subject: [PATCH 05/14] feat: add interval for schedules --- cmd/vela-server/main.go | 8 +++++++- cmd/vela-server/server.go | 12 +++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index 19463fe0b..788f6c26b 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.go @@ -213,9 +213,15 @@ func main() { &cli.DurationFlag{ EnvVars: []string{"VELA_SCHEDULE_MINIMUM_FREQUENCY", "SCHEDULE_MINIMUM_FREQUENCY"}, Name: "schedule-minimum-frequency", - Usage: "minimum time between each schedule entry", + Usage: "minimum time allowed between each build triggered for a schedule", Value: 1 * time.Hour, }, + &cli.DurationFlag{ + EnvVars: []string{"VELA_SCHEDULE_INTERVAL", "SCHEDULE_INTERVAL"}, + Name: "schedule-interval", + Usage: "interval at which schedules will be processed by the server to trigger builds", + Value: 5 * time.Minute, + }, &cli.StringSliceFlag{ EnvVars: []string{"VELA_SCHEDULE_ALLOWLIST"}, Name: "vela-schedule-allowlist", diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 0d95e88e5..df21aaf5f 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -176,12 +176,10 @@ func server(c *cli.Context) error { g.Go(func() error { logrus.Info("starting scheduler") for { - // cut the configured minimum frequency duration for schedules in half - // // We need to sleep for some amount of time before we attempt to process schedules - // setup in the database. Since the minimum frequency is configurable, we cut it in - // half and use that as the base duration to determine how long to sleep for. - base := c.Duration("schedule-minimum-frequency") / 2 + // setup in the database. Since the schedule interval is configurable, we use that + // as the base duration to determine how long to sleep for. + base := c.Duration("schedule-interval") logrus.Infof("sleeping for %v before scheduling builds", base) // sleep for a duration of time before processing schedules @@ -189,8 +187,8 @@ func server(c *cli.Context) error { // This should prevent multiple servers from processing schedules at the same time by // leveraging a base duration along with a standard deviation of randomness a.k.a. // "jitter". To create the jitter, we use the configured minimum frequency duration - // along with a scale factor of 0.1. - time.Sleep(wait.Jitter(base, 0.1)) + // along with a scale factor of 0.5. + time.Sleep(wait.Jitter(base, 0.5)) err = processSchedules(compiler, database, metadata, queue, scm) if err != nil { From cc3b18cd9a00e1e50a64d0f3d6bfd9aa19291cdb Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Tue, 27 Jun 2023 08:16:26 -0500 Subject: [PATCH 06/14] chore: address slack feedback --- cmd/vela-server/schedule.go | 65 +++++++++++++++---------------------- cmd/vela-server/server.go | 13 ++++---- 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 309360177..1cbc38749 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -26,7 +26,7 @@ import ( const baseErr = "unable to schedule build" -func processSchedules(compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { +func processSchedules(base time.Duration, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { logrus.Infof("processing active schedules to create builds") // send API call to capture the list of active schedules @@ -37,23 +37,6 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met // iterate through the list of active schedules for _, s := range schedules { - gron := gronx.New() - - // check if the schedule is due based off the entry accounting for UTC - due, err := gron.IsDue(s.GetEntry(), time.Now().UTC()) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, s.GetName()) - - continue - } - - // check if the schedule is due to trigger a build - if !due { - logrus.Tracef("waiting to schedule build for %s", s.GetName()) - - continue - } - // send API call to capture the schedule // // This is needed to ensure we are not dealing with a stale schedule since we fetch @@ -73,33 +56,37 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met continue } - // check if a build has already been triggered for the schedule - if schedule.GetScheduledAt() > 0 { - // parse the previous occurrence of the entry for the schedule - prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + // capture the previous occurrence of the entry for the schedule rounded to the nearest whole interval + // + // i.e. if it's 4:02 on five minute intervals, this will be 4:00 + prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, s.GetName()) - continue - } + continue + } - // parse the next occurrence of the entry for the schedule - nextTime, err := gronx.NextTick(schedule.GetEntry(), true) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + // capture the next occurrence of the entry for the schedule rounded to the nearest whole interval + // + // i.e. if it's 4:02 on five minute intervals, this will be 4:05 + nextTime, err := gronx.NextTick(schedule.GetEntry(), true) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, s.GetName()) - continue - } + continue + } - // parse the UNIX timestamp from when the last build was triggered for the schedule - t := time.Unix(schedule.GetScheduledAt(), 0).UTC() + // determine if schedule is due for processing + // + // The current time must be past the next occurrence and the current time (minus sweep gap) must be + // after the previous occurrence to ensure the schedule will run at the correct time. + due := time.Now().After(nextTime) && prevTime.After(time.Now().Add(-base)) - // check if the time since the last triggered build is less than the entry duration for the schedule - if time.Since(t) < nextTime.Sub(prevTime) { - logrus.Tracef("waiting to schedule build for %s", s.GetName()) + // check if the schedule is due to trigger a build + if !due { + logrus.Tracef("waiting to schedule build for %s", s.GetName()) - continue - } + continue } // process the schedule and trigger a new build diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index df21aaf5f..7d399b88d 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -180,17 +180,18 @@ func server(c *cli.Context) error { // setup in the database. Since the schedule interval is configurable, we use that // as the base duration to determine how long to sleep for. base := c.Duration("schedule-interval") - logrus.Infof("sleeping for %v before scheduling builds", base) - // sleep for a duration of time before processing schedules - // // This should prevent multiple servers from processing schedules at the same time by // leveraging a base duration along with a standard deviation of randomness a.k.a. - // "jitter". To create the jitter, we use the configured minimum frequency duration + // "jitter". To create the jitter, we use the configured schedule interval duration // along with a scale factor of 0.5. - time.Sleep(wait.Jitter(base, 0.5)) + jitter := wait.Jitter(base, 0.5) + + logrus.Infof("sleeping for %v before scheduling builds", jitter) + // sleep for a duration of time before processing schedules + time.Sleep(jitter) - err = processSchedules(compiler, database, metadata, queue, scm) + err = processSchedules(base, compiler, database, metadata, queue, scm) if err != nil { logrus.WithError(err).Warn("unable to process schedules") } else { From e0840d52b27a94425d0d4a500f58b12068d867e9 Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Tue, 27 Jun 2023 08:58:29 -0500 Subject: [PATCH 07/14] chore: fix typos --- cmd/vela-server/schedule.go | 8 ++++---- cmd/vela-server/server.go | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 0dac80a99..5bcaf8772 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -26,7 +26,7 @@ import ( const baseErr = "unable to schedule build" -func processSchedules(base time.Duration, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { +func processSchedules(interval time.Duration, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { logrus.Infof("processing active schedules to create builds") // send API call to capture the list of active schedules @@ -78,9 +78,9 @@ func processSchedules(base time.Duration, compiler compiler.Engine, database dat // determine if schedule is due for processing // - // The current time must be past the next occurrence and the current time (minus sweep gap) must be - // after the previous occurrence to ensure the schedule will run at the correct time. - due := time.Now().After(nextTime) && prevTime.After(time.Now().Add(-base)) + // The current time must be past the next occurrence and the current time (minus schedule interval) + // must be after the previous occurrence to ensure the schedule will run at the correct time. + due := time.Now().After(nextTime) && prevTime.After(time.Now().Add(-interval)) // check if the schedule is due to trigger a build if !due { diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 7d399b88d..595d0ce68 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -179,19 +179,19 @@ func server(c *cli.Context) error { // We need to sleep for some amount of time before we attempt to process schedules // setup in the database. Since the schedule interval is configurable, we use that // as the base duration to determine how long to sleep for. - base := c.Duration("schedule-interval") + interval := c.Duration("schedule-interval") // This should prevent multiple servers from processing schedules at the same time by // leveraging a base duration along with a standard deviation of randomness a.k.a. // "jitter". To create the jitter, we use the configured schedule interval duration // along with a scale factor of 0.5. - jitter := wait.Jitter(base, 0.5) + jitter := wait.Jitter(interval, 0.5) logrus.Infof("sleeping for %v before scheduling builds", jitter) // sleep for a duration of time before processing schedules time.Sleep(jitter) - err = processSchedules(base, compiler, database, metadata, queue, scm) + err = processSchedules(interval, compiler, database, metadata, queue, scm) if err != nil { logrus.WithError(err).Warn("unable to process schedules") } else { From 6d54f53e429dc19ab774b3642e990c854c75f399 Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Tue, 27 Jun 2023 13:37:54 -0500 Subject: [PATCH 08/14] fix: processing timed schedules --- cmd/vela-server/schedule.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 5bcaf8772..a759df9de 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -66,24 +66,30 @@ func processSchedules(interval time.Duration, compiler compiler.Engine, database continue } - // capture the next occurrence of the entry for the schedule rounded to the nearest whole interval + // capture the next occurrence of the entry after the last schedule rounded to the nearest whole interval // // i.e. if it's 4:02 on five minute intervals, this will be 4:05 - nextTime, err := gronx.NextTick(schedule.GetEntry(), true) + nextTime, err := gronx.NextTickAfter(s.GetEntry(), time.Unix(s.GetScheduledAt(), 0).UTC(), true) if err != nil { logrus.WithError(err).Warnf("%s for %s", baseErr, s.GetName()) continue } - // determine if schedule is due for processing + // check if we should wait to trigger a build for the schedule // - // The current time must be past the next occurrence and the current time (minus schedule interval) - // must be after the previous occurrence to ensure the schedule will run at the correct time. - due := time.Now().After(nextTime) && prevTime.After(time.Now().Add(-interval)) + // The current time must be after the next occurrence of the schedule. + if !time.Now().After(nextTime) { + logrus.Tracef("waiting to schedule build for %s", s.GetName()) - // check if the schedule is due to trigger a build - if !due { + continue + } + + // check if we should wait to trigger a build for the schedule + // + // The current time minus the schedule interval (with jitter as a buffer) + // must be after the previous occurrence of the schedule. + if !prevTime.After(time.Now().Add(-wait.Jitter(interval, 0.5))) { logrus.Tracef("waiting to schedule build for %s", s.GetName()) continue From afd763e4ed2b30dd5e6a65b7bd5b5b6ba092992e Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Mon, 3 Jul 2023 09:23:46 -0500 Subject: [PATCH 09/14] fix: processing schedules --- cmd/vela-server/schedule.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index a759df9de..ca6ec7c1e 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -87,9 +87,9 @@ func processSchedules(interval time.Duration, compiler compiler.Engine, database // check if we should wait to trigger a build for the schedule // - // The current time minus the schedule interval (with jitter as a buffer) - // must be after the previous occurrence of the schedule. - if !prevTime.After(time.Now().Add(-wait.Jitter(interval, 0.5))) { + // The interval for the schedule (multiplied by 2 as a buffer) subtracted from + // the current must be after the previous occurrence of the schedule. + if !prevTime.After(time.Now().Add(-(2 * interval))) { logrus.Tracef("waiting to schedule build for %s", s.GetName()) continue @@ -113,8 +113,8 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat // // This should prevent multiple servers from processing a schedule at the same time by // leveraging a base duration along with a standard deviation of randomness a.k.a. - // "jitter". To create the jitter, we use a base duration of 1s with a scale factor of 3.0. - time.Sleep(wait.Jitter(time.Second, 3.0)) + // "jitter". To create the jitter, we use a base duration of 1s with a scale factor of 2.0. + time.Sleep(wait.Jitter(time.Second, 2.0)) // send API call to capture the repo for the schedule r, err := database.GetRepo(s.GetRepoID()) From 691aec25378eb07496a01f5d0a0a74a6b40f8a36 Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Mon, 3 Jul 2023 09:31:58 -0500 Subject: [PATCH 10/14] fix: typo in comment --- cmd/vela-server/schedule.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index ca6ec7c1e..7668292d3 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -88,7 +88,7 @@ func processSchedules(interval time.Duration, compiler compiler.Engine, database // check if we should wait to trigger a build for the schedule // // The interval for the schedule (multiplied by 2 as a buffer) subtracted from - // the current must be after the previous occurrence of the schedule. + // the current time must be after the previous occurrence of the schedule. if !prevTime.After(time.Now().Add(-(2 * interval))) { logrus.Tracef("waiting to schedule build for %s", s.GetName()) From c7faed2152a7573f5aa8e61b342c36c38cb70db1 Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Thu, 6 Jul 2023 14:32:34 -0500 Subject: [PATCH 11/14] chore: address review feedback --- cmd/vela-server/schedule.go | 52 +++++++++++++++++++++---------------- cmd/vela-server/server.go | 10 ++++++- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 7668292d3..682b938af 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -9,6 +9,8 @@ import ( "strings" "time" + "k8s.io/apimachinery/pkg/util/wait" + "github.com/adhocore/gronx" "github.com/go-vela/server/api/build" "github.com/go-vela/server/compiler" @@ -20,13 +22,15 @@ import ( "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" "github.com/sirupsen/logrus" - - "k8s.io/apimachinery/pkg/util/wait" ) -const baseErr = "unable to schedule build" +const ( + scheduleErr = "unable to trigger build for schedule" + + scheduleWait = "waiting to trigger build for schedule" +) -func processSchedules(interval time.Duration, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { +func processSchedules(start time.Time, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { logrus.Infof("processing active schedules to create builds") // send API call to capture the list of active schedules @@ -37,6 +41,13 @@ func processSchedules(interval time.Duration, compiler compiler.Engine, database // iterate through the list of active schedules for _, s := range schedules { + // sleep for 1s - 2s before processing the active schedule + // + // This should prevent multiple servers from processing a schedule at the same time by + // leveraging a base duration along with a standard deviation of randomness a.k.a. + // "jitter". To create the jitter, we use a base duration of 1s with a scale factor of 1.0. + time.Sleep(wait.Jitter(time.Second, 1.0)) + // send API call to capture the schedule // // This is needed to ensure we are not dealing with a stale schedule since we fetch @@ -44,24 +55,27 @@ func processSchedules(interval time.Duration, compiler compiler.Engine, database // amount of time to get to the end of the list. schedule, err := database.GetSchedule(s.GetID()) if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) continue } // ignore triggering a build if the schedule is no longer active if !schedule.GetActive() { - logrus.Tracef("ignoring to schedule build for %s", s.GetName()) + logrus.Tracef("skipping to trigger build for inactive schedule %s", schedule.GetName()) continue } - // capture the previous occurrence of the entry for the schedule rounded to the nearest whole interval + // capture the last time a build was triggered for the schedule in UTC + scheduled := time.Unix(schedule.GetScheduledAt(), 0).UTC() + + // capture the previous occurrence of the entry rounded to the nearest whole interval // // i.e. if it's 4:02 on five minute intervals, this will be 4:00 prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, s.GetName()) + logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) continue } @@ -69,9 +83,9 @@ func processSchedules(interval time.Duration, compiler compiler.Engine, database // capture the next occurrence of the entry after the last schedule rounded to the nearest whole interval // // i.e. if it's 4:02 on five minute intervals, this will be 4:05 - nextTime, err := gronx.NextTickAfter(s.GetEntry(), time.Unix(s.GetScheduledAt(), 0).UTC(), true) + nextTime, err := gronx.NextTickAfter(schedule.GetEntry(), scheduled, true) if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, s.GetName()) + logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) continue } @@ -80,17 +94,16 @@ func processSchedules(interval time.Duration, compiler compiler.Engine, database // // The current time must be after the next occurrence of the schedule. if !time.Now().After(nextTime) { - logrus.Tracef("waiting to schedule build for %s", s.GetName()) + logrus.Tracef("%s %s: current time not past next occurrence", scheduleWait, schedule.GetName()) continue } // check if we should wait to trigger a build for the schedule // - // The interval for the schedule (multiplied by 2 as a buffer) subtracted from - // the current time must be after the previous occurrence of the schedule. - if !prevTime.After(time.Now().Add(-(2 * interval))) { - logrus.Tracef("waiting to schedule build for %s", s.GetName()) + // The previous occurrence of the schedule must be after the starting time of processing schedules. + if !prevTime.After(start) { + logrus.Tracef("%s %s: previous occurence not after starting point", scheduleWait, schedule.GetName()) continue } @@ -98,7 +111,7 @@ func processSchedules(interval time.Duration, compiler compiler.Engine, database // process the schedule and trigger a new build err = processSchedule(schedule, compiler, database, metadata, queue, scm) if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) continue } @@ -109,13 +122,6 @@ func processSchedules(interval time.Duration, compiler compiler.Engine, database //nolint:funlen // ignore function length and number of statements func processSchedule(s *library.Schedule, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { - // sleep for 1s - 3s before processing the schedule - // - // This should prevent multiple servers from processing a schedule at the same time by - // leveraging a base duration along with a standard deviation of randomness a.k.a. - // "jitter". To create the jitter, we use a base duration of 1s with a scale factor of 2.0. - time.Sleep(wait.Jitter(time.Second, 2.0)) - // send API call to capture the repo for the schedule r, err := database.GetRepo(s.GetRepoID()) if err != nil { diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 595d0ce68..689ba03c2 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -176,6 +176,14 @@ func server(c *cli.Context) error { g.Go(func() error { logrus.Info("starting scheduler") for { + // track the starting time for when the server begins processing schedules + // + // This will be used to control which schedules will have a build triggered based + // off the configured entry and last time a build was triggered for the schedule. + start := time.Now().UTC() + + // capture the interval of time to wait before processing schedules + // // We need to sleep for some amount of time before we attempt to process schedules // setup in the database. Since the schedule interval is configurable, we use that // as the base duration to determine how long to sleep for. @@ -191,7 +199,7 @@ func server(c *cli.Context) error { // sleep for a duration of time before processing schedules time.Sleep(jitter) - err = processSchedules(interval, compiler, database, metadata, queue, scm) + err = processSchedules(start, compiler, database, metadata, queue, scm) if err != nil { logrus.WithError(err).Warn("unable to process schedules") } else { From 9d1621345de2332b100d421debf64fc97663eaf4 Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Thu, 6 Jul 2023 14:32:53 -0500 Subject: [PATCH 12/14] temp: add test docker compose --- test-docker-compose.yml | 302 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 test-docker-compose.yml diff --git a/test-docker-compose.yml b/test-docker-compose.yml new file mode 100644 index 000000000..a5ae46c96 --- /dev/null +++ b/test-docker-compose.yml @@ -0,0 +1,302 @@ +# NOTE: This file was originally copied from the './docker-compose.yml'. +# +# It should be removed before https://github.com/go-vela/server/pull/893 is merged. +# +# It contains 5 'server' Docker services to enable testing the processing of schedules with multiple servers. + +version: '3' + +services: + + server: + build: + context: . + dockerfile: Dockerfile + container_name: server + image: server:local + networks: + - vela + environment: + DATABASE_DRIVER: postgres + DATABASE_ADDR: 'postgres://vela:zB7mrKDTZqNeNTD8z47yG4DHywspAh@postgres:5432/vela?sslmode=disable' + DATABASE_COMPRESSION_LEVEL: 3 + DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' + QUEUE_DRIVER: redis + QUEUE_ADDR: 'redis://redis:6379' + SCM_DRIVER: github + SCM_CONTEXT: 'continuous-integration/vela' + SECRET_VAULT: 'true' + SECRET_VAULT_ADDR: 'http://vault:8200' + SECRET_VAULT_TOKEN: vela + VELA_ADDR: 'http://localhost:8080' + VELA_WEBUI_ADDR: 'http://localhost:8888' + VELA_LOG_LEVEL: trace + VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' + VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' + VELA_USER_REFRESH_TOKEN_DURATION: 90m + VELA_USER_ACCESS_TOKEN_DURATION: 60m + VELA_DISABLE_WEBHOOK_VALIDATION: 'true' + VELA_ENABLE_SECURE_COOKIE: 'false' + VELA_REPO_ALLOWLIST: '*' + VELA_SCHEDULE_ALLOWLIST: '*' + VELA_SCHEDULE_INTERVAL: '1m' + VELA_SCHEDULE_MINIMUM_FREQUENCY: 1m + env_file: + - .env + restart: always + ports: + - '8080:8080' + depends_on: + - postgres + - redis + - vault + + server1: + build: + context: . + dockerfile: Dockerfile + container_name: server1 + image: server:local + networks: + - vela + environment: + DATABASE_DRIVER: postgres + DATABASE_ADDR: 'postgres://vela:zB7mrKDTZqNeNTD8z47yG4DHywspAh@postgres:5432/vela?sslmode=disable' + DATABASE_COMPRESSION_LEVEL: 3 + DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' + QUEUE_DRIVER: redis + QUEUE_ADDR: 'redis://redis:6379' + SCM_DRIVER: github + SCM_CONTEXT: 'continuous-integration/vela' + SECRET_VAULT: 'true' + SECRET_VAULT_ADDR: 'http://vault:8200' + SECRET_VAULT_TOKEN: vela + VELA_ADDR: 'http://localhost:8080' + VELA_WEBUI_ADDR: 'http://localhost:8888' + VELA_LOG_LEVEL: trace + VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' + VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' + VELA_USER_REFRESH_TOKEN_DURATION: 90m + VELA_USER_ACCESS_TOKEN_DURATION: 60m + VELA_DISABLE_WEBHOOK_VALIDATION: 'true' + VELA_ENABLE_SECURE_COOKIE: 'false' + VELA_REPO_ALLOWLIST: '*' + VELA_SCHEDULE_ALLOWLIST: '*' + VELA_SCHEDULE_INTERVAL: '1m' + VELA_SCHEDULE_MINIMUM_FREQUENCY: 1m + env_file: + - .env + restart: always + ports: + - '8082:8080' + depends_on: + - postgres + - redis + - vault + + server2: + build: + context: . + dockerfile: Dockerfile + container_name: server2 + image: server:local + networks: + - vela + environment: + DATABASE_DRIVER: postgres + DATABASE_ADDR: 'postgres://vela:zB7mrKDTZqNeNTD8z47yG4DHywspAh@postgres:5432/vela?sslmode=disable' + DATABASE_COMPRESSION_LEVEL: 3 + DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' + QUEUE_DRIVER: redis + QUEUE_ADDR: 'redis://redis:6379' + SCM_DRIVER: github + SCM_CONTEXT: 'continuous-integration/vela' + SECRET_VAULT: 'true' + SECRET_VAULT_ADDR: 'http://vault:8200' + SECRET_VAULT_TOKEN: vela + VELA_ADDR: 'http://localhost:8080' + VELA_WEBUI_ADDR: 'http://localhost:8888' + VELA_LOG_LEVEL: trace + VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' + VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' + VELA_USER_REFRESH_TOKEN_DURATION: 90m + VELA_USER_ACCESS_TOKEN_DURATION: 60m + VELA_DISABLE_WEBHOOK_VALIDATION: 'true' + VELA_ENABLE_SECURE_COOKIE: 'false' + VELA_REPO_ALLOWLIST: '*' + VELA_SCHEDULE_ALLOWLIST: '*' + VELA_SCHEDULE_INTERVAL: '1m' + VELA_SCHEDULE_MINIMUM_FREQUENCY: 1m + env_file: + - .env + restart: always + ports: + - '8083:8080' + depends_on: + - postgres + - redis + - vault + + server3: + build: + context: . + dockerfile: Dockerfile + container_name: server3 + image: server:local + networks: + - vela + environment: + DATABASE_DRIVER: postgres + DATABASE_ADDR: 'postgres://vela:zB7mrKDTZqNeNTD8z47yG4DHywspAh@postgres:5432/vela?sslmode=disable' + DATABASE_COMPRESSION_LEVEL: 3 + DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' + QUEUE_DRIVER: redis + QUEUE_ADDR: 'redis://redis:6379' + SCM_DRIVER: github + SCM_CONTEXT: 'continuous-integration/vela' + SECRET_VAULT: 'true' + SECRET_VAULT_ADDR: 'http://vault:8200' + SECRET_VAULT_TOKEN: vela + VELA_ADDR: 'http://localhost:8080' + VELA_WEBUI_ADDR: 'http://localhost:8888' + VELA_LOG_LEVEL: trace + VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' + VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' + VELA_USER_REFRESH_TOKEN_DURATION: 90m + VELA_USER_ACCESS_TOKEN_DURATION: 60m + VELA_DISABLE_WEBHOOK_VALIDATION: 'true' + VELA_ENABLE_SECURE_COOKIE: 'false' + VELA_REPO_ALLOWLIST: '*' + VELA_SCHEDULE_ALLOWLIST: '*' + VELA_SCHEDULE_INTERVAL: '1m' + VELA_SCHEDULE_MINIMUM_FREQUENCY: 1m + env_file: + - .env + restart: always + ports: + - '8084:8080' + depends_on: + - postgres + - redis + - vault + + server4: + build: + context: . + dockerfile: Dockerfile + container_name: server4 + image: server:local + networks: + - vela + environment: + DATABASE_DRIVER: postgres + DATABASE_ADDR: 'postgres://vela:zB7mrKDTZqNeNTD8z47yG4DHywspAh@postgres:5432/vela?sslmode=disable' + DATABASE_COMPRESSION_LEVEL: 3 + DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' + QUEUE_DRIVER: redis + QUEUE_ADDR: 'redis://redis:6379' + SCM_DRIVER: github + SCM_CONTEXT: 'continuous-integration/vela' + SECRET_VAULT: 'true' + SECRET_VAULT_ADDR: 'http://vault:8200' + SECRET_VAULT_TOKEN: vela + VELA_ADDR: 'http://localhost:8080' + VELA_WEBUI_ADDR: 'http://localhost:8888' + VELA_LOG_LEVEL: trace + VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' + VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' + VELA_USER_REFRESH_TOKEN_DURATION: 90m + VELA_USER_ACCESS_TOKEN_DURATION: 60m + VELA_DISABLE_WEBHOOK_VALIDATION: 'true' + VELA_ENABLE_SECURE_COOKIE: 'false' + VELA_REPO_ALLOWLIST: '*' + VELA_SCHEDULE_ALLOWLIST: '*' + VELA_SCHEDULE_INTERVAL: '1m' + VELA_SCHEDULE_MINIMUM_FREQUENCY: 1m + env_file: + - .env + restart: always + ports: + - '8085:8080' + depends_on: + - postgres + - redis + - vault + + worker: + container_name: worker + image: target/vela-worker:latest + networks: + - vela + environment: + EXECUTOR_DRIVER: linux + QUEUE_DRIVER: redis + QUEUE_ADDR: 'redis://redis:6379' + VELA_BUILD_LIMIT: 1 + VELA_BUILD_TIMEOUT: 30m + VELA_LOG_LEVEL: trace + VELA_RUNTIME_DRIVER: docker + VELA_RUNTIME_PRIVILEGED_IMAGES: 'target/vela-docker' + VELA_SERVER_ADDR: 'http://server:8080' + VELA_SERVER_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' + WORKER_ADDR: 'http://worker:8080' + WORKER_CHECK_IN: 5m + restart: always + ports: + - '8081:8080' + volumes: + - '/var/run/docker.sock:/var/run/docker.sock' + depends_on: + - server + + ui: + container_name: ui + image: target/vela-ui:latest + networks: + - vela + env_file: + - .env + environment: + VELA_API: http://localhost:8080 + restart: always + ports: + - '8888:80' + depends_on: + - server + + redis: + container_name: redis + image: redis:7-alpine + networks: + - vela + ports: + - '6379:6379' + + postgres: + container_name: postgres + image: postgres:15-alpine + networks: + - vela + environment: + POSTGRES_DB: vela + POSTGRES_PASSWORD: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' + POSTGRES_USER: vela + ports: + - '5432:5432' + + vault: + image: hashicorp/vault:latest + container_name: vault + command: server -dev + networks: + - vela + environment: + VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200 + VAULT_DEV_ROOT_TOKEN_ID: vela + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + +networks: + vela: \ No newline at end of file From c3648d2992bb33f51960cd750d421b2d7c6eb448 Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Fri, 7 Jul 2023 13:51:51 -0500 Subject: [PATCH 13/14] fix: finalize --- cmd/vela-server/schedule.go | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 682b938af..08e7867cc 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -9,8 +9,6 @@ import ( "strings" "time" - "k8s.io/apimachinery/pkg/util/wait" - "github.com/adhocore/gronx" "github.com/go-vela/server/api/build" "github.com/go-vela/server/compiler" @@ -22,6 +20,8 @@ import ( "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" "github.com/sirupsen/logrus" + + "k8s.io/apimachinery/pkg/util/wait" ) const ( @@ -108,6 +108,20 @@ func processSchedules(start time.Time, compiler compiler.Engine, database databa continue } + // update the scheduled_at field with the current timestamp + // + // This should help prevent multiple servers from processing a schedule at the same time + // by updating the schedule with a new timestamp to reflect the current state. + schedule.SetScheduledAt(time.Now().UTC().Unix()) + + // send API call to update schedule for ensuring scheduled_at field is set + err = database.UpdateSchedule(schedule, false) + if err != nil { + logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) + + continue + } + // process the schedule and trigger a new build err = processSchedule(schedule, compiler, database, metadata, queue, scm) if err != nil { @@ -354,8 +368,6 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat return err } - s.SetScheduledAt(time.Now().UTC().Unix()) - // break the loop because everything was successful break } // end of retry loop @@ -366,12 +378,6 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat return fmt.Errorf("unable to update repo %s: %w", r.GetFullName(), err) } - // send API call to update schedule for ensuring scheduled_at field is set - err = database.UpdateSchedule(s, false) - if err != nil { - return fmt.Errorf("unable to update schedule %s/%s: %w", r.GetFullName(), s.GetName(), err) - } - // send API call to capture the triggered build b, err = database.GetBuildForRepo(r, b.GetNumber()) if err != nil { From 0b2ef323e42483967726e083a6ec10d3f0bc9994 Mon Sep 17 00:00:00 2001 From: JordanBrockopp Date: Fri, 7 Jul 2023 13:52:27 -0500 Subject: [PATCH 14/14] revert: add test docker compose --- test-docker-compose.yml | 302 ---------------------------------------- 1 file changed, 302 deletions(-) delete mode 100644 test-docker-compose.yml diff --git a/test-docker-compose.yml b/test-docker-compose.yml deleted file mode 100644 index a5ae46c96..000000000 --- a/test-docker-compose.yml +++ /dev/null @@ -1,302 +0,0 @@ -# NOTE: This file was originally copied from the './docker-compose.yml'. -# -# It should be removed before https://github.com/go-vela/server/pull/893 is merged. -# -# It contains 5 'server' Docker services to enable testing the processing of schedules with multiple servers. - -version: '3' - -services: - - server: - build: - context: . - dockerfile: Dockerfile - container_name: server - image: server:local - networks: - - vela - environment: - DATABASE_DRIVER: postgres - DATABASE_ADDR: 'postgres://vela:zB7mrKDTZqNeNTD8z47yG4DHywspAh@postgres:5432/vela?sslmode=disable' - DATABASE_COMPRESSION_LEVEL: 3 - DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' - QUEUE_DRIVER: redis - QUEUE_ADDR: 'redis://redis:6379' - SCM_DRIVER: github - SCM_CONTEXT: 'continuous-integration/vela' - SECRET_VAULT: 'true' - SECRET_VAULT_ADDR: 'http://vault:8200' - SECRET_VAULT_TOKEN: vela - VELA_ADDR: 'http://localhost:8080' - VELA_WEBUI_ADDR: 'http://localhost:8888' - VELA_LOG_LEVEL: trace - VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' - VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' - VELA_USER_REFRESH_TOKEN_DURATION: 90m - VELA_USER_ACCESS_TOKEN_DURATION: 60m - VELA_DISABLE_WEBHOOK_VALIDATION: 'true' - VELA_ENABLE_SECURE_COOKIE: 'false' - VELA_REPO_ALLOWLIST: '*' - VELA_SCHEDULE_ALLOWLIST: '*' - VELA_SCHEDULE_INTERVAL: '1m' - VELA_SCHEDULE_MINIMUM_FREQUENCY: 1m - env_file: - - .env - restart: always - ports: - - '8080:8080' - depends_on: - - postgres - - redis - - vault - - server1: - build: - context: . - dockerfile: Dockerfile - container_name: server1 - image: server:local - networks: - - vela - environment: - DATABASE_DRIVER: postgres - DATABASE_ADDR: 'postgres://vela:zB7mrKDTZqNeNTD8z47yG4DHywspAh@postgres:5432/vela?sslmode=disable' - DATABASE_COMPRESSION_LEVEL: 3 - DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' - QUEUE_DRIVER: redis - QUEUE_ADDR: 'redis://redis:6379' - SCM_DRIVER: github - SCM_CONTEXT: 'continuous-integration/vela' - SECRET_VAULT: 'true' - SECRET_VAULT_ADDR: 'http://vault:8200' - SECRET_VAULT_TOKEN: vela - VELA_ADDR: 'http://localhost:8080' - VELA_WEBUI_ADDR: 'http://localhost:8888' - VELA_LOG_LEVEL: trace - VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' - VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' - VELA_USER_REFRESH_TOKEN_DURATION: 90m - VELA_USER_ACCESS_TOKEN_DURATION: 60m - VELA_DISABLE_WEBHOOK_VALIDATION: 'true' - VELA_ENABLE_SECURE_COOKIE: 'false' - VELA_REPO_ALLOWLIST: '*' - VELA_SCHEDULE_ALLOWLIST: '*' - VELA_SCHEDULE_INTERVAL: '1m' - VELA_SCHEDULE_MINIMUM_FREQUENCY: 1m - env_file: - - .env - restart: always - ports: - - '8082:8080' - depends_on: - - postgres - - redis - - vault - - server2: - build: - context: . - dockerfile: Dockerfile - container_name: server2 - image: server:local - networks: - - vela - environment: - DATABASE_DRIVER: postgres - DATABASE_ADDR: 'postgres://vela:zB7mrKDTZqNeNTD8z47yG4DHywspAh@postgres:5432/vela?sslmode=disable' - DATABASE_COMPRESSION_LEVEL: 3 - DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' - QUEUE_DRIVER: redis - QUEUE_ADDR: 'redis://redis:6379' - SCM_DRIVER: github - SCM_CONTEXT: 'continuous-integration/vela' - SECRET_VAULT: 'true' - SECRET_VAULT_ADDR: 'http://vault:8200' - SECRET_VAULT_TOKEN: vela - VELA_ADDR: 'http://localhost:8080' - VELA_WEBUI_ADDR: 'http://localhost:8888' - VELA_LOG_LEVEL: trace - VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' - VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' - VELA_USER_REFRESH_TOKEN_DURATION: 90m - VELA_USER_ACCESS_TOKEN_DURATION: 60m - VELA_DISABLE_WEBHOOK_VALIDATION: 'true' - VELA_ENABLE_SECURE_COOKIE: 'false' - VELA_REPO_ALLOWLIST: '*' - VELA_SCHEDULE_ALLOWLIST: '*' - VELA_SCHEDULE_INTERVAL: '1m' - VELA_SCHEDULE_MINIMUM_FREQUENCY: 1m - env_file: - - .env - restart: always - ports: - - '8083:8080' - depends_on: - - postgres - - redis - - vault - - server3: - build: - context: . - dockerfile: Dockerfile - container_name: server3 - image: server:local - networks: - - vela - environment: - DATABASE_DRIVER: postgres - DATABASE_ADDR: 'postgres://vela:zB7mrKDTZqNeNTD8z47yG4DHywspAh@postgres:5432/vela?sslmode=disable' - DATABASE_COMPRESSION_LEVEL: 3 - DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' - QUEUE_DRIVER: redis - QUEUE_ADDR: 'redis://redis:6379' - SCM_DRIVER: github - SCM_CONTEXT: 'continuous-integration/vela' - SECRET_VAULT: 'true' - SECRET_VAULT_ADDR: 'http://vault:8200' - SECRET_VAULT_TOKEN: vela - VELA_ADDR: 'http://localhost:8080' - VELA_WEBUI_ADDR: 'http://localhost:8888' - VELA_LOG_LEVEL: trace - VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' - VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' - VELA_USER_REFRESH_TOKEN_DURATION: 90m - VELA_USER_ACCESS_TOKEN_DURATION: 60m - VELA_DISABLE_WEBHOOK_VALIDATION: 'true' - VELA_ENABLE_SECURE_COOKIE: 'false' - VELA_REPO_ALLOWLIST: '*' - VELA_SCHEDULE_ALLOWLIST: '*' - VELA_SCHEDULE_INTERVAL: '1m' - VELA_SCHEDULE_MINIMUM_FREQUENCY: 1m - env_file: - - .env - restart: always - ports: - - '8084:8080' - depends_on: - - postgres - - redis - - vault - - server4: - build: - context: . - dockerfile: Dockerfile - container_name: server4 - image: server:local - networks: - - vela - environment: - DATABASE_DRIVER: postgres - DATABASE_ADDR: 'postgres://vela:zB7mrKDTZqNeNTD8z47yG4DHywspAh@postgres:5432/vela?sslmode=disable' - DATABASE_COMPRESSION_LEVEL: 3 - DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' - QUEUE_DRIVER: redis - QUEUE_ADDR: 'redis://redis:6379' - SCM_DRIVER: github - SCM_CONTEXT: 'continuous-integration/vela' - SECRET_VAULT: 'true' - SECRET_VAULT_ADDR: 'http://vault:8200' - SECRET_VAULT_TOKEN: vela - VELA_ADDR: 'http://localhost:8080' - VELA_WEBUI_ADDR: 'http://localhost:8888' - VELA_LOG_LEVEL: trace - VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' - VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' - VELA_USER_REFRESH_TOKEN_DURATION: 90m - VELA_USER_ACCESS_TOKEN_DURATION: 60m - VELA_DISABLE_WEBHOOK_VALIDATION: 'true' - VELA_ENABLE_SECURE_COOKIE: 'false' - VELA_REPO_ALLOWLIST: '*' - VELA_SCHEDULE_ALLOWLIST: '*' - VELA_SCHEDULE_INTERVAL: '1m' - VELA_SCHEDULE_MINIMUM_FREQUENCY: 1m - env_file: - - .env - restart: always - ports: - - '8085:8080' - depends_on: - - postgres - - redis - - vault - - worker: - container_name: worker - image: target/vela-worker:latest - networks: - - vela - environment: - EXECUTOR_DRIVER: linux - QUEUE_DRIVER: redis - QUEUE_ADDR: 'redis://redis:6379' - VELA_BUILD_LIMIT: 1 - VELA_BUILD_TIMEOUT: 30m - VELA_LOG_LEVEL: trace - VELA_RUNTIME_DRIVER: docker - VELA_RUNTIME_PRIVILEGED_IMAGES: 'target/vela-docker' - VELA_SERVER_ADDR: 'http://server:8080' - VELA_SERVER_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' - WORKER_ADDR: 'http://worker:8080' - WORKER_CHECK_IN: 5m - restart: always - ports: - - '8081:8080' - volumes: - - '/var/run/docker.sock:/var/run/docker.sock' - depends_on: - - server - - ui: - container_name: ui - image: target/vela-ui:latest - networks: - - vela - env_file: - - .env - environment: - VELA_API: http://localhost:8080 - restart: always - ports: - - '8888:80' - depends_on: - - server - - redis: - container_name: redis - image: redis:7-alpine - networks: - - vela - ports: - - '6379:6379' - - postgres: - container_name: postgres - image: postgres:15-alpine - networks: - - vela - environment: - POSTGRES_DB: vela - POSTGRES_PASSWORD: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' - POSTGRES_USER: vela - ports: - - '5432:5432' - - vault: - image: hashicorp/vault:latest - container_name: vault - command: server -dev - networks: - - vela - environment: - VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200 - VAULT_DEV_ROOT_TOKEN_ID: vela - ports: - - '8200:8200' - cap_add: - - IPC_LOCK - -networks: - vela: \ No newline at end of file