mirror of
https://github.com/grafana/grafana.git
synced 2025-08-02 11:02:55 +08:00
Redshift: Support caching async aws queries (#71682)
Co-authored-by: Sarah Zinger <sarah.zinger@grafana.com>
This commit is contained in:
@ -2,19 +2,31 @@ package clientmiddleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/caching"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// needed to mock the function for testing
|
||||
var shouldCacheQuery = awsds.ShouldCacheQuery
|
||||
|
||||
// NewCachingMiddleware creates a new plugins.ClientMiddleware that will
|
||||
// attempt to read and write query results to the cache
|
||||
func NewCachingMiddleware(cachingService caching.CachingService) plugins.ClientMiddleware {
|
||||
return NewCachingMiddlewareWithFeatureManager(cachingService, nil)
|
||||
}
|
||||
|
||||
// NewCachingMiddlewareWithFeatureManager creates a new plugins.ClientMiddleware that will
|
||||
// attempt to read and write query results to the cache with a feature manager
|
||||
func NewCachingMiddlewareWithFeatureManager(cachingService caching.CachingService, features *featuremgmt.FeatureManager) plugins.ClientMiddleware {
|
||||
log := log.New("caching_middleware")
|
||||
if err := prometheus.Register(QueryCachingRequestHistogram); err != nil {
|
||||
log.Error("error registering prometheus collector 'QueryRequestHistogram'", "error", err)
|
||||
@ -24,17 +36,19 @@ func NewCachingMiddleware(cachingService caching.CachingService) plugins.ClientM
|
||||
}
|
||||
return plugins.ClientMiddlewareFunc(func(next plugins.Client) plugins.Client {
|
||||
return &CachingMiddleware{
|
||||
next: next,
|
||||
caching: cachingService,
|
||||
log: log,
|
||||
next: next,
|
||||
caching: cachingService,
|
||||
log: log,
|
||||
features: features,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type CachingMiddleware struct {
|
||||
next plugins.Client
|
||||
caching caching.CachingService
|
||||
log log.Logger
|
||||
next plugins.Client
|
||||
caching caching.CachingService
|
||||
log log.Logger
|
||||
features *featuremgmt.FeatureManager
|
||||
}
|
||||
|
||||
// QueryData receives a data request and attempts to access results already stored in the cache for that request.
|
||||
@ -57,7 +71,8 @@ func (m *CachingMiddleware) QueryData(ctx context.Context, req *backend.QueryDat
|
||||
hit, cr := m.caching.HandleQueryRequest(ctx, req)
|
||||
|
||||
// record request duration if caching was used
|
||||
if ch := reqCtx.Resp.Header().Get(caching.XCacheHeader); ch != "" {
|
||||
ch := reqCtx.Resp.Header().Get(caching.XCacheHeader)
|
||||
if ch != "" {
|
||||
defer func() {
|
||||
QueryCachingRequestHistogram.With(prometheus.Labels{
|
||||
"datasource_type": req.PluginContext.DataSourceInstanceSettings.Type,
|
||||
@ -77,7 +92,25 @@ func (m *CachingMiddleware) QueryData(ctx context.Context, req *backend.QueryDat
|
||||
|
||||
// Update the query cache with the result for this metrics request
|
||||
if err == nil && cr.UpdateCacheFn != nil {
|
||||
cr.UpdateCacheFn(ctx, resp)
|
||||
// If AWS async caching is not enabled, use the old code path
|
||||
if m.features == nil || !m.features.IsEnabled(featuremgmt.FlagAwsAsyncQueryCaching) {
|
||||
cr.UpdateCacheFn(ctx, resp)
|
||||
} else {
|
||||
// time how long shouldCacheQuery takes
|
||||
startShouldCacheQuery := time.Now()
|
||||
shouldCache := shouldCacheQuery(resp)
|
||||
ShouldCacheQueryHistogram.With(prometheus.Labels{
|
||||
"datasource_type": req.PluginContext.DataSourceInstanceSettings.Type,
|
||||
"cache": ch,
|
||||
"shouldCache": strconv.FormatBool(shouldCache),
|
||||
"query_type": getQueryType(reqCtx),
|
||||
}).Observe(time.Since(startShouldCacheQuery).Seconds())
|
||||
|
||||
// If AWS async caching is enabled and resp is for a running async query, don't cache it
|
||||
if shouldCache {
|
||||
cr.UpdateCacheFn(ctx, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
|
Reference in New Issue
Block a user