Introduce query timeout configuration (#2157)

## Summary

Implements configurable query execution timeout controls to prevent
poorly optimized or excessive queries from consuming excessive server
resources, causing performance degradation, or crashing the Zabbix
server.

Fixes: https://github.com/grafana/oss-big-tent-squad/issues/127

## Problem

Previously, the plugin only had an HTTP connection timeout (`timeout`)
that controlled individual API request timeouts. However, a complete
query execution could involve multiple API calls and run indefinitely if
not properly controlled, potentially causing resource exhaustion.

## Solution

Added a new `queryTimeout` setting that enforces a maximum execution
time for entire database queries initiated by the plugin. Queries
exceeding this limit are automatically terminated with proper error
handling and logging.

## Testing

1. Configure a datasource with `queryTimeout` set to a low value (e.g.,
5 seconds)
2. Execute a query that would normally take longer than the timeout
3. Verify that:
   - Query is terminated after the timeout period
   - Error message indicates timeout occurred
   - Logs contain timeout warning with query details
   - Other queries in the same request continue to execute

## Notes

- `queryTimeout` is separate from `timeout` (HTTP connection timeout)
- `queryTimeout` applies to the entire query execution, which may
involve multiple API calls
- Default value of 60 seconds ensures reasonable protection while
allowing normal queries to complete
- Timeout errors are logged with query refId, queryType, timeout
duration, and datasourceId for troubleshooting
This commit is contained in:
ismail simsek
2026-01-12 15:30:31 +01:00
committed by GitHub
parent 7eb80d3f23
commit a2f8b6433a
7 changed files with 366 additions and 50 deletions

View File

@@ -78,6 +78,7 @@ export const ConfigEditor = (props: Props) => {
trendsRange: '',
cacheTTL: '',
timeout: undefined,
queryTimeout: undefined,
disableDataAlignment: false,
...restJsonData,
},
@@ -238,6 +239,44 @@ export const ConfigEditor = (props: Props) => {
</Field>
</ConfigSubSection>
<ConfigSubSection title="Query Options">
<Field
label={
<Label>
<EditorStack gap={0.5}>
<span>Query Timeout</span>
<Tooltip
content={
<span>
Maximum execution time in seconds for database queries initiated by the plugin. Queries
exceeding this limit will be automatically terminated. Default is 60 seconds.
</span>
}
>
<Icon name="info-circle" size="sm" />
</Tooltip>
</EditorStack>
</Label>
}
>
<Input
width={40}
type="number"
value={options.jsonData.queryTimeout}
placeholder="60"
onChange={(event) => {
onOptionsChange({
...options,
jsonData: {
...options.jsonData,
queryTimeout: parseInt(event.currentTarget.value, 10) || undefined,
},
});
}}
/>
</Field>
</ConfigSubSection>
<ConfigSubSection title="Trends">
<Field label="Enable Trends">
<Switch

View File

@@ -14,6 +14,7 @@ export type ZabbixDSOptions = {
trendsRange: string;
cacheTTL: string;
timeout?: number;
queryTimeout?: number;
dbConnectionEnable: boolean;
dbConnectionDatasourceId?: number;
dbConnectionDatasourceName?: string;