func (mr *MultiRunner) requestBuild(runner *common.RunnerConfig) *common.Build { if runner == nil { return nil } if !mr.isHealthy(runner) { return nil } count := mr.buildsForRunner(runner) limit := helpers.NonZeroOrDefault(runner.Limit, math.MaxInt32) if count >= limit { return nil } buildData, healthy := common.GetBuild(*runner) if healthy { mr.makeHealthy(runner) } else { mr.makeUnhealthy(runner) } if buildData == nil { return nil } mr.debugln("Received new build for", runner.ShortDescription(), "build", buildData.ID) newBuild := &common.Build{ GetBuildResponse: *buildData, Runner: runner, BuildAbort: mr.abortBuilds, } return newBuild }
func runSingle(c *cli.Context) { buildsDir := c.String("builds-dir") shell := c.String("shell") config := common.NewConfig() runner := common.RunnerConfig{ URL: c.String("url"), Token: c.String("token"), Executor: c.String("executor"), BuildsDir: &buildsDir, Shell: &shell, } if len(runner.URL) == 0 { log.Fatalln("Missing URL") } if len(runner.Token) == 0 { log.Fatalln("Missing Token") } if len(runner.Executor) == 0 { log.Fatalln("Missing Executor") } go runServer(c.String("addr")) go runHerokuURL(c.String("heroku-url")) signals := make(chan os.Signal) signal.Notify(signals, os.Interrupt, syscall.SIGTERM) log.Println("Starting runner for", runner.URL, "with token", runner.ShortDescription(), "...") finished := false abortSignal := make(chan os.Signal) doneSignal := make(chan int, 1) go func() { interrupt := <-signals log.Warningln("Requested exit:", interrupt) finished = true go func() { for { abortSignal <- interrupt } }() select { case newSignal := <-signals: log.Fatalln("forced exit:", newSignal) case <-time.After(common.ShutdownTimeout * time.Second): log.Fatalln("shutdown timedout") case <-doneSignal: } }() for !finished { buildData, healthy := common.GetBuild(runner) if !healthy { log.Println("Runner is not healthy!") select { case <-time.After(common.NotHealthyCheckInterval * time.Second): case <-abortSignal: } continue } if buildData == nil { select { case <-time.After(common.CheckInterval * time.Second): case <-abortSignal: } continue } newBuild := common.Build{ GetBuildResponse: *buildData, Runner: &runner, BuildAbort: abortSignal, } newBuild.AssignID() newBuild.Run(config) } doneSignal <- 0 }
func (r *RunSingleCommand) Execute(c *cli.Context) { if len(r.URL) == 0 { log.Fatalln("Missing URL") } if len(r.Token) == 0 { log.Fatalln("Missing Token") } if len(r.Executor) == 0 { log.Fatalln("Missing Executor") } config := common.NewConfig() signals := make(chan os.Signal) signal.Notify(signals, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT) log.Println("Starting runner for", r.URL, "with token", r.ShortDescription(), "...") finished := false abortSignal := make(chan os.Signal) doneSignal := make(chan int, 1) go func() { interrupt := <-signals finished = true // request stop, but wait for force exit for interrupt == syscall.SIGQUIT { log.Warningln("Requested quit, waiting for builds to finish") interrupt = <-signals } log.Warningln("Requested exit:", interrupt) go func() { for { abortSignal <- interrupt } }() select { case newSignal := <-signals: log.Fatalln("forced exit:", newSignal) case <-time.After(common.ShutdownTimeout * time.Second): log.Fatalln("shutdown timedout") case <-doneSignal: } }() for !finished { buildData, healthy := common.GetBuild(r.RunnerConfig) if !healthy { log.Println("Runner is not healthy!") select { case <-time.After(common.NotHealthyCheckInterval * time.Second): case <-abortSignal: } continue } if buildData == nil { select { case <-time.After(common.CheckInterval * time.Second): case <-abortSignal: } continue } newBuild := common.Build{ GetBuildResponse: *buildData, Runner: &r.RunnerConfig, BuildAbort: abortSignal, } newBuild.AssignID() newBuild.Run(config) } doneSignal <- 0 }