From 62efe6e1706f6a90c91a0ae0cabf6939cd3e5f87 Mon Sep 17 00:00:00 2001 From: Dominik Prokop Date: Wed, 14 Feb 2024 09:19:39 -0800 Subject: [PATCH] Panel Query Options: Support query caching options (#82448) * schema update * Panel Query Options: Support query caching options --- .../kinds/core/dashboard/schema-reference.md | 4 +++ kinds/dashboard/dashboard_kind.cue | 6 ++++ .../raw/dashboard/x/dashboard_types.gen.ts | 8 +++++ pkg/kinds/dashboard/dashboard_spec_gen.go | 6 ++++ .../PanelDataPane/PanelDataQueriesTab.tsx | 9 ++++-- .../panel-edit/VizPanelManager.test.tsx | 24 ++++++++++++++ .../panel-edit/VizPanelManager.tsx | 8 +++++ .../transformSaveModelToScene.test.ts | 16 ++++++++++ .../transformSceneToSaveModel.test.ts | 31 +++++++++++++++++++ .../transformSceneToSaveModel.ts | 13 +++++++- .../utils/createPanelDataProvider.ts | 2 ++ 11 files changed, 123 insertions(+), 4 deletions(-) diff --git a/docs/sources/developers/kinds/core/dashboard/schema-reference.md b/docs/sources/developers/kinds/core/dashboard/schema-reference.md index 561580fd2fd..0bbf32a8c27 100644 --- a/docs/sources/developers/kinds/core/dashboard/schema-reference.md +++ b/docs/sources/developers/kinds/core/dashboard/schema-reference.md @@ -436,6 +436,7 @@ Dashboard panels are the basic visualization building blocks. | Property | Type | Required | Default | Description | |--------------------|---------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `type` | string | **Yes** | | The panel plugin type id. This is used to find the plugin to display the panel.
Constraint: `length >=1`. | +| `cacheTimeout` | string | No | | Sets panel queries cache timeout. | | `datasource` | [DataSourceRef](#datasourceref) | No | | Ref to a DataSource instance | | `description` | string | No | | Panel description. | | `fieldConfig` | [FieldConfigSource](#fieldconfigsource) | No | | The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results.
Each column within this structure is called a field. A field can represent a single time series or table column.
Field options allow you to change how the data is displayed in your visualizations. | @@ -449,6 +450,7 @@ Dashboard panels are the basic visualization building blocks. | `maxPerRow` | number | No | | Option for repeated panels that controls max items per row
Only relevant for horizontally repeated panels | | `options` | [object](#options) | No | | It depends on the panel plugin. They are specified by the Options field in panel plugin schemas. | | `pluginVersion` | string | No | | The version of the plugin that is used for this panel. This is used to find the plugin to display the panel and to migrate old panel configs. | +| `queryCachingTTL` | number | No | | Overrides the data source configured time-to-live for a query cache item in milliseconds | | `repeatDirection` | string | No | `h` | Direction to repeat in if 'repeat' is set.
`h` for horizontal, `v` for vertical.
Possible values are: `h`, `v`. | | `repeat` | string | No | | Name of template variable to repeat for. | | `targets` | [Target](#target)[] | No | | Depends on the panel plugin. See the plugin documentation for details. | @@ -500,6 +502,7 @@ Dashboard panels are the basic visualization building blocks. | Property | Type | Required | Default | Description | |--------------------|---------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `type` | string | **Yes** | | The panel plugin type id. This is used to find the plugin to display the panel.
Constraint: `length >=1`. | +| `cacheTimeout` | string | No | | Sets panel queries cache timeout. | | `datasource` | [DataSourceRef](#datasourceref) | No | | Ref to a DataSource instance | | `description` | string | No | | Panel description. | | `fieldConfig` | [FieldConfigSource](#fieldconfigsource) | No | | The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results.
Each column within this structure is called a field. A field can represent a single time series or table column.
Field options allow you to change how the data is displayed in your visualizations. | @@ -513,6 +516,7 @@ Dashboard panels are the basic visualization building blocks. | `maxPerRow` | number | No | | Option for repeated panels that controls max items per row
Only relevant for horizontally repeated panels | | `options` | [options](#options) | No | | It depends on the panel plugin. They are specified by the Options field in panel plugin schemas. | | `pluginVersion` | string | No | | The version of the plugin that is used for this panel. This is used to find the plugin to display the panel and to migrate old panel configs. | +| `queryCachingTTL` | number | No | | Overrides the data source configured time-to-live for a query cache item in milliseconds | | `repeatDirection` | string | No | `h` | Direction to repeat in if 'repeat' is set.
`h` for horizontal, `v` for vertical.
Possible values are: `h`, `v`. | | `repeat` | string | No | | Name of template variable to repeat for. | | `targets` | [Target](#target)[] | No | | Depends on the panel plugin. See the plugin documentation for details. | diff --git a/kinds/dashboard/dashboard_kind.cue b/kinds/dashboard/dashboard_kind.cue index fe963ef5bab..b366e2c96ff 100644 --- a/kinds/dashboard/dashboard_kind.cue +++ b/kinds/dashboard/dashboard_kind.cue @@ -591,6 +591,12 @@ lineage: schemas: [{ // Dynamically load the panel libraryPanel?: #LibraryPanelRef + // Sets panel queries cache timeout. + cacheTimeout?: string + + // Overrides the data source configured time-to-live for a query cache item in milliseconds + queryCachingTTL?: number + // It depends on the panel plugin. They are specified by the Options field in panel plugin schemas. options?: {...} @grafanamaturity(NeedsExpertReview) diff --git a/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts b/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts index 3e7d114de76..886dd0e3466 100644 --- a/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts +++ b/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts @@ -692,6 +692,10 @@ export const defaultDashboardCursorSync: DashboardCursorSync = DashboardCursorSy * Dashboard panels are the basic visualization building blocks. */ export interface Panel { + /** + * Sets panel queries cache timeout. + */ + cacheTimeout?: string; /** * The datasource used in all targets. */ @@ -748,6 +752,10 @@ export interface Panel { * The version of the plugin that is used for this panel. This is used to find the plugin to display the panel and to migrate old panel configs. */ pluginVersion?: string; + /** + * Overrides the data source configured time-to-live for a query cache item in milliseconds + */ + queryCachingTTL?: number; /** * Name of template variable to repeat for. */ diff --git a/pkg/kinds/dashboard/dashboard_spec_gen.go b/pkg/kinds/dashboard/dashboard_spec_gen.go index 3014bba97ef..ab33a177135 100644 --- a/pkg/kinds/dashboard/dashboard_spec_gen.go +++ b/pkg/kinds/dashboard/dashboard_spec_gen.go @@ -505,6 +505,9 @@ type MatcherConfig struct { // Dashboard panels are the basic visualization building blocks. type Panel struct { + // Sets panel queries cache timeout. + CacheTimeout *string `json:"cacheTimeout,omitempty"` + // Ref to a DataSource instance Datasource *DataSourceRef `json:"datasource,omitempty"` @@ -552,6 +555,9 @@ type Panel struct { // The version of the plugin that is used for this panel. This is used to find the plugin to display the panel and to migrate old panel configs. PluginVersion *string `json:"pluginVersion,omitempty"` + // Overrides the data source configured time-to-live for a query cache item in milliseconds + QueryCachingTTL *float32 `json:"queryCachingTTL,omitempty"` + // Name of template variable to repeat for. Repeat *string `json:"repeat,omitempty"` diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx index 164237f0ae2..1f47fdabe5a 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx @@ -72,9 +72,12 @@ export class PanelDataQueriesTab extends SceneObjectBase { expect(dataObj.state.minInterval).toBe('1s'); }); }); + + describe('query caching', () => { + it('updates cacheTimeout and queryCachingTTL', async () => { + const { vizPanelManager } = setupTest('panel-1'); + vizPanelManager.activate(); + await Promise.resolve(); + + const dataObj = vizPanelManager.queryRunner; + + vizPanelManager.changeQueryOptions({ + cacheTimeout: '60', + queryCachingTTL: 200000, + dataSource: { + name: 'grafana-testdata', + type: 'grafana-testdata-datasource', + default: true, + }, + queries: [], + }); + + expect(dataObj.state.cacheTimeout).toBe('60'); + expect(dataObj.state.queryCachingTTL).toBe(200000); + }); + }); }); describe('query inspection', () => { diff --git a/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx b/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx index 3c40e06957c..6a87c2c64c5 100644 --- a/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx +++ b/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx @@ -229,6 +229,14 @@ export class VizPanelManager extends SceneObjectBase { panelObj.setState({ $timeRange: new PanelTimeRange(timeRangeObjStateUpdate) }); } + if (options.cacheTimeout !== dataObj?.state.cacheTimeout) { + dataObjStateUpdate.cacheTimeout = options.cacheTimeout; + } + + if (options.queryCachingTTL !== dataObj?.state.queryCachingTTL) { + dataObjStateUpdate.queryCachingTTL = options.queryCachingTTL; + } + dataObj.setState(dataObjStateUpdate); dataObj.runQueries(); } diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts index 52f8757b376..490732bf0ee 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts @@ -443,6 +443,22 @@ describe('transformSaveModelToScene', () => { expect(repeater.state.repeatDirection).toBe('v'); expect(repeater.state.maxPerRow).toBe(8); }); + + it('should apply query caching options to SceneQueryRunner', () => { + const panel = { + title: '', + type: 'test-plugin', + gridPos: { x: 0, y: 0, w: 12, h: 8 }, + transparent: true, + cacheTimeout: '10', + queryCachingTTL: 200000, + }; + + const { vizPanel } = buildGridItemForTest(panel); + const runner = getQueryRunnerFor(vizPanel)!; + expect(runner.state.cacheTimeout).toBe('10'); + expect(runner.state.queryCachingTTL).toBe(200000); + }); }); describe('when creating variables objects', () => { diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts index 86b675a6f81..2901b087238 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts @@ -564,6 +564,37 @@ describe('transformSceneToSaveModel', () => { uid: SHARED_DASHBOARD_QUERY, }); }); + + it('Given panel with query caching options', () => { + const panel = buildGridItemFromPanelSchema({ + datasource: { + type: 'grafana-testdata', + uid: 'abc', + }, + cacheTimeout: '10', + queryCachingTTL: 200000, + maxDataPoints: 100, + targets: [ + { + refId: 'A', + expr: 'A', + datasource: { + type: 'grafana-testdata', + uid: 'abc', + }, + }, + { + refId: 'B', + expr: 'B', + }, + ], + }); + + const result = gridItemToPanel(panel); + + expect(result.cacheTimeout).toBe('10'); + expect(result.queryCachingTTL).toBe(200000); + }); }); describe('Snapshots', () => { diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts index 84442df1153..e6301ac4ef7 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts @@ -251,13 +251,24 @@ function vizPanelDataToPanel( ): Pick { const dataProvider = vizPanel.state.$data; - const panel: Pick = {}; + const panel: Pick< + Panel, + 'datasource' | 'targets' | 'maxDataPoints' | 'transformations' | 'cacheTimeout' | 'queryCachingTTL' + > = {}; const queryRunner = getQueryRunnerFor(vizPanel); if (queryRunner) { panel.targets = queryRunner.state.queries; panel.maxDataPoints = queryRunner.state.maxDataPoints; panel.datasource = queryRunner.state.datasource; + + if (queryRunner.state.cacheTimeout) { + panel.cacheTimeout = queryRunner.state.cacheTimeout; + } + + if (queryRunner.state.queryCachingTTL) { + panel.queryCachingTTL = queryRunner.state.queryCachingTTL; + } } if (dataProvider instanceof SceneDataTransformer) { diff --git a/public/app/features/dashboard-scene/utils/createPanelDataProvider.ts b/public/app/features/dashboard-scene/utils/createPanelDataProvider.ts index 6e58e8fa398..774ff4c31c3 100644 --- a/public/app/features/dashboard-scene/utils/createPanelDataProvider.ts +++ b/public/app/features/dashboard-scene/utils/createPanelDataProvider.ts @@ -20,6 +20,8 @@ export function createPanelDataProvider(panel: PanelModel): SceneDataProvider | queries: panel.targets, maxDataPoints: panel.maxDataPoints ?? undefined, maxDataPointsFromWidth: true, + cacheTimeout: panel.cacheTimeout, + queryCachingTTL: panel.queryCachingTTL, dataLayerFilter: { panelId: panel.id, },