From c3b9b31f9d0b1cc27ada118b7c48986a32707368 Mon Sep 17 00:00:00 2001 From: Mark Rappoport Date: Mon, 9 Aug 2021 17:12:02 +0300 Subject: [PATCH 1/2] allow adjustable number of rendering workers via MAX_WORKERS envar --- report/report.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/report/report.go b/report/report.go index 9d354a5..eb2d88f 100644 --- a/report/report.go +++ b/report/report.go @@ -20,9 +20,12 @@ import ( "fmt" "io" "log" + "math" "os" "os/exec" "path/filepath" + "runtime" + "strconv" "sync" "text/template" @@ -72,6 +75,15 @@ func new(g grafana.Client, dashName string, time grafana.TimeRange, texTemplate return &report{g, time, texTemplate, dashName, tmpDir, ""} } +func (rep *report) getWorkerNum() int { + var ( + desiredWorkers, _ = strconv.Atoi(os.Getenv("MAX_WORKERS")) + maxWorkers = runtime.NumCPU() + ) + desiredWorkers = int(math.Max(1, math.Min(float64(desiredWorkers), float64(maxWorkers)))) + return desiredWorkers +} + // Generate returns the report.pdf file. After reading this file it should be Closed() // After closing the file, call report.Clean() to delete the file as well the temporary build files func (rep *report) Generate() (pdf io.ReadCloser, err error) { @@ -141,8 +153,7 @@ func (rep *report) renderPNGsParallel(dash grafana.Dashboard) error { //limit concurrency using a worker pool to avoid overwhelming grafana //for dashboards with many panels. var wg sync.WaitGroup - workers := 5 - wg.Add(workers) + wg.Add(rep.getWorkerNum()) errs := make(chan error, len(dash.Panels)) //routines can return errors on a channel for i := 0; i < workers; i++ { go func(panels <-chan grafana.Panel, errs chan<- error) { From b70b07b53416c74185c76cfad6a5b3c5dbeb97e4 Mon Sep 17 00:00:00 2001 From: Mark R Date: Mon, 9 Aug 2021 20:15:22 +0300 Subject: [PATCH 2/2] Cleanup worker assignment --- report/report.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/report/report.go b/report/report.go index eb2d88f..d7e55b0 100644 --- a/report/report.go +++ b/report/report.go @@ -142,6 +142,10 @@ func (rep *report) texPath() string { } func (rep *report) renderPNGsParallel(dash grafana.Dashboard) error { + var ( + wg sync.WaitGroup + workers = rep.getWorkerNum() + ) //buffer all panels on a channel panels := make(chan grafana.Panel, len(dash.Panels)) for _, p := range dash.Panels { @@ -152,8 +156,8 @@ func (rep *report) renderPNGsParallel(dash grafana.Dashboard) error { //fetch images in parrallel form Grafana sever. //limit concurrency using a worker pool to avoid overwhelming grafana //for dashboards with many panels. - var wg sync.WaitGroup - wg.Add(rep.getWorkerNum()) + + wg.Add(workers) errs := make(chan error, len(dash.Panels)) //routines can return errors on a channel for i := 0; i < workers; i++ { go func(panels <-chan grafana.Panel, errs chan<- error) {