Skip to content

Commit

Permalink
⭐️ Randomize the start time of scanning in serve mode
Browse files Browse the repository at this point in the history
This makes sure that scans get randomly distributed throughout the timer
time in an effort to spread out load against the api server.
  • Loading branch information
jaym committed Jun 23, 2023
1 parent 715e024 commit 914627e
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 17 deletions.
5 changes: 4 additions & 1 deletion apps/cnspec/cmd/backgroundjob/background.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ func New() (*BackgroundScanner, error) {
type BackgroundScanner struct{}

func (bs *BackgroundScanner) Run(runScanFn JobRunner) error {
Serve(time.Duration(viper.GetInt64("timer"))*time.Minute, runScanFn)
Serve(
time.Duration(viper.GetInt64("timer"))*time.Minute,
time.Duration(viper.GetInt64("splay"))*time.Minute,
runScanFn)
return nil
}
20 changes: 11 additions & 9 deletions apps/cnspec/cmd/backgroundjob/serve_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package backgroundjob

import (
"math/rand"
"os"
"os/signal"
"sync"
Expand All @@ -13,19 +14,20 @@ import (
"github.com/rs/zerolog/log"
)

func Serve(timer time.Duration, handler JobRunner) {
func Serve(timer time.Duration, splay time.Duration, handler JobRunner) {
log.Info().Msg("start cnspec background service")
log.Info().Msgf("scan interval is %d minute(s)", int(timer.Minutes()))
log.Info().Msgf("scan interval is %d minute(s) with a splay of %d minutes(s)", int(timer.Minutes()), int(splay.Minutes()))

quitChannel := make(chan os.Signal)
signal.Notify(quitChannel, syscall.SIGINT, syscall.SIGTERM)

shutdownChannel := make(chan struct{})
waitGroup := &sync.WaitGroup{}

initTick := time.Tick(1 * time.Second)
defaultTick := time.Tick(timer)
tick := initTick
t := time.NewTimer(time.Duration(rand.Int63n(int64(time.Minute))))
defer t.Stop()

//tick := initTick
waitGroup.Add(1)

go func(shutdownChannel chan struct{}, wg *sync.WaitGroup) {
Expand All @@ -40,14 +42,14 @@ func Serve(timer time.Duration, handler JobRunner) {
}

select {
case <-tick:
if tick == initTick {
tick = defaultTick
}
case <-t.C:
err := handler()
if err != nil {
log.Error().Err(err).Send()
}
nextRun := timer + time.Duration(rand.Int63n(int64(splay)))
log.Info().Msgf("next scan in %v", nextRun)
t.Reset(nextRun)
case <-shutdownChannel:
log.Info().Msg("stop worker")
return
Expand Down
15 changes: 8 additions & 7 deletions apps/cnspec/cmd/backgroundjob/serve_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ type windowsService struct {
func (m *windowsService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
changes <- svc.Status{State: svc.StartPending}
initTick := time.Tick(1 * time.Second)
defaulttick := time.Tick(m.Timer)
tick := initTick

t := time.NewTimer(time.Duration(rand.Int63n(int64(time.Minute))))
defer t.Stop()

log.Info().Msg("schedule background scan")
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}

Expand All @@ -68,15 +69,15 @@ func (m *windowsService) Execute(args []string, r <-chan svc.ChangeRequest, chan
loop:
for {
select {
case <-tick:
if tick == initTick {
tick = defaulttick
}
case <-t.C:
select {
case runChan <- struct{}{}:
default:
log.Error().Msg("scan not started. may be stuck")
}
nextRun := timer + time.Duration(rand.Int63n(int64(splay)))
log.Info().Msgf("next scan in %v", nextRun)
t.Reset(nextRun)
case c := <-r:
switch c.Cmd {
case svc.Interrogate:
Expand Down
3 changes: 3 additions & 0 deletions apps/cnspec/cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ func init() {
rootCmd.AddCommand(serveCmd)
// background scan flags
serveCmd.Flags().Int("timer", 60, "scan interval in minutes")
serveCmd.Flags().Int("splay", 60, "randomize the timer by up to this many minutes")
serveCmd.Flags().MarkHidden("timer")
serveCmd.Flags().MarkHidden("splay")
// set inventory
serveCmd.Flags().String("inventory-file", "", "Set the path to the inventory file")
}
Expand All @@ -47,6 +49,7 @@ var serveCmd = &cobra.Command{

PreRun: func(cmd *cobra.Command, args []string) {
viper.BindPFlag("timer", cmd.Flags().Lookup("timer"))
viper.BindPFlag("splay", cmd.Flags().Lookup("splay"))
viper.BindPFlag("inventory-file", cmd.Flags().Lookup("inventory-file"))
},
Run: func(cmd *cobra.Command, args []string) {
Expand Down

0 comments on commit 914627e

Please sign in to comment.