diff --git a/pkg/api/render.go b/pkg/api/render.go index 582c6ec1e4b..5db0b88fa35 100644 --- a/pkg/api/render.go +++ b/pkg/api/render.go @@ -98,6 +98,11 @@ func (hs *HTTPServer) RenderHandler(c *contextmodel.ReqContext) { Theme: themeModel, }, nil) if err != nil { + if errors.Is(err, rendering.ErrTooManyRequests) { + c.JsonApiErr(http.StatusTooManyRequests, "Too many rendering requests", err) + return + } + if errors.Is(err, rendering.ErrTimeout) { c.Handle(hs.Cfg, http.StatusInternalServerError, err.Error(), err) return diff --git a/pkg/services/rendering/http_mode.go b/pkg/services/rendering/http_mode.go index 705f9672240..ea15eb389e5 100644 --- a/pkg/services/rendering/http_mode.go +++ b/pkg/services/rendering/http_mode.go @@ -31,6 +31,7 @@ var netClient = &http.Client{ } const authTokenHeader = "X-Auth-Token" //#nosec G101 -- This is a false positive +const rateLimiterHeader = "X-Tenant-ID" var ( remoteVersionFetchInterval time.Duration = time.Second * 15 @@ -160,6 +161,7 @@ func (rs *RenderingService) doRequest(ctx context.Context, u *url.URL, headers m } req.Header.Set(authTokenHeader, rs.Cfg.RendererAuthToken) + req.Header.Set(rateLimiterHeader, rs.domain) req.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", rs.Cfg.BuildVersion)) for k, v := range headers { req.Header[k] = v @@ -180,6 +182,10 @@ func (rs *RenderingService) doRequest(ctx context.Context, u *url.URL, headers m return nil, fmt.Errorf("failed to send request to remote rendering service: %w", err) } + if resp.StatusCode == http.StatusTooManyRequests { + return nil, ErrTooManyRequests + } + return resp, nil } diff --git a/pkg/services/rendering/interface.go b/pkg/services/rendering/interface.go index 9b5b2f17cdc..a54d2b92560 100644 --- a/pkg/services/rendering/interface.go +++ b/pkg/services/rendering/interface.go @@ -14,6 +14,7 @@ var ErrTimeout = errors.New("timeout error - you can set timeout in seconds with var ErrConcurrentLimitReached = errors.New("rendering concurrent limit reached") var ErrRenderUnavailable = errors.New("rendering plugin not available") var ErrServerTimeout = errutil.NewBase(errutil.StatusUnknown, "rendering.serverTimeout", errutil.WithPublicMessage("error trying to connect to image-renderer service")) +var ErrTooManyRequests = errutil.NewBase(errutil.StatusTooManyRequests, "rendering.tooManyRequests", errutil.WithPublicMessage("trying to send too many requests to image-renderer service")) type RenderType string