fix: remove buffer period (#2078)

* fix: remove buffer period

* app/vmselect/vmui: `make vmui-update`

* docs/CHANGELOG.md: document the implemented feature

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2064

Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
Yury Molodov 2022-01-18 22:42:56 +03:00 committed by GitHub
parent 70737ea4ac
commit 8bdc45ba00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 30 additions and 35 deletions

View File

@ -1,12 +1,12 @@
{ {
"files": { "files": {
"main.css": "./static/css/main.79ff1ad2.css", "main.css": "./static/css/main.79ff1ad2.css",
"main.js": "./static/js/main.7d03dd65.js", "main.js": "./static/js/main.96282d01.js",
"static/js/27.cc1b69f7.chunk.js": "./static/js/27.cc1b69f7.chunk.js", "static/js/27.cc1b69f7.chunk.js": "./static/js/27.cc1b69f7.chunk.js",
"index.html": "./index.html" "index.html": "./index.html"
}, },
"entrypoints": [ "entrypoints": [
"static/css/main.79ff1ad2.css", "static/css/main.79ff1ad2.css",
"static/js/main.7d03dd65.js" "static/js/main.96282d01.js"
] ]
} }

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><script defer="defer" src="./static/js/main.7d03dd65.js"></script><link href="./static/css/main.79ff1ad2.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html> <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><script defer="defer" src="./static/js/main.96282d01.js"></script><link href="./static/css/main.79ff1ad2.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

View File

@ -1,12 +1,13 @@
import {useEffect, useMemo, useState} from "preact/compat"; import {useEffect, useMemo, useCallback, useState} from "preact/compat";
import {getQueryOptions, getQueryRangeUrl, getQueryUrl} from "../../../../api/query-range"; import {getQueryOptions, getQueryRangeUrl, getQueryUrl} from "../../../../api/query-range";
import {useAppState} from "../../../../state/common/StateContext"; import {useAppState} from "../../../../state/common/StateContext";
import {InstantMetricResult, MetricBase, MetricResult} from "../../../../api/types"; import {InstantMetricResult, MetricBase, MetricResult} from "../../../../api/types";
import {isValidHttpUrl} from "../../../../utils/url"; import {isValidHttpUrl} from "../../../../utils/url";
import {useAuthState} from "../../../../state/auth/AuthStateContext"; import {useAuthState} from "../../../../state/auth/AuthStateContext";
import {ErrorTypes, TimeParams} from "../../../../types"; import {ErrorTypes} from "../../../../types";
import {useGraphState} from "../../../../state/graph/GraphStateContext"; import {useGraphState} from "../../../../state/graph/GraphStateContext";
import {getAppModeEnable, getAppModeParams} from "../../../../utils/app-mode"; import {getAppModeEnable, getAppModeParams} from "../../../../utils/app-mode";
import throttle from "lodash.throttle";
const appModeEnable = getAppModeEnable(); const appModeEnable = getAppModeEnable();
const {serverURL: appServerUrl} = getAppModeParams(); const {serverURL: appServerUrl} = getAppModeParams();
@ -19,7 +20,7 @@ export const useFetchQuery = (): {
error?: ErrorTypes | string, error?: ErrorTypes | string,
queryOptions: string[], queryOptions: string[],
} => { } => {
const {query, displayType, serverUrl, time: {period}, queryControls: {nocache, autoRefresh}} = useAppState(); const {query, displayType, serverUrl, time: {period}, queryControls: {nocache}} = useAppState();
const {basicData, bearerData, authMethod} = useAuthState(); const {basicData, bearerData, authMethod} = useAuthState();
const {customStep} = useGraphState(); const {customStep} = useGraphState();
@ -29,7 +30,7 @@ export const useFetchQuery = (): {
const [graphData, setGraphData] = useState<MetricResult[]>(); const [graphData, setGraphData] = useState<MetricResult[]>();
const [liveData, setLiveData] = useState<InstantMetricResult[]>(); const [liveData, setLiveData] = useState<InstantMetricResult[]>();
const [error, setError] = useState<ErrorTypes | string>(); const [error, setError] = useState<ErrorTypes | string>();
const [prevPeriod, setPrevPeriod] = useState<TimeParams>(); const [fetchQueue, setFetchQueue] = useState<AbortController[]>([]);
useEffect(() => { useEffect(() => {
if (error) { if (error) {
@ -38,19 +39,11 @@ export const useFetchQuery = (): {
} }
}, [error]); }, [error]);
const needUpdateData = useMemo(() => { const fetchData = async (fetchUrl: string[] | undefined) => {
if (!prevPeriod || autoRefresh) return true;
const duration = (prevPeriod.end - prevPeriod.start) / 3;
const factorLimit = duration / (period.end - period.start) >= 0.7;
const maxLimit = period.end > (prevPeriod.end + duration);
const minLimit = period.start < (prevPeriod.start - duration);
return factorLimit || maxLimit || minLimit;
}, [period]);
const fetchData = async () => {
if (!fetchUrl?.length) return; if (!fetchUrl?.length) return;
const controller = new AbortController();
setFetchQueue([...fetchQueue, controller]);
setIsLoading(true); setIsLoading(true);
setPrevPeriod(period);
const headers = new Headers(); const headers = new Headers();
if (authMethod === "BASIC_AUTH") { if (authMethod === "BASIC_AUTH") {
@ -61,7 +54,7 @@ export const useFetchQuery = (): {
} }
try { try {
const responses = await Promise.all(fetchUrl.map(url => fetch(url, {headers}))); const responses = await Promise.all(fetchUrl.map(url => fetch(url, {headers, signal: controller.signal})));
const tempData = []; const tempData = [];
let counter = 1; let counter = 1;
for await (const response of responses) { for await (const response of responses) {
@ -79,12 +72,16 @@ export const useFetchQuery = (): {
} }
displayType === "chart" ? setGraphData(tempData) : setLiveData(tempData); displayType === "chart" ? setGraphData(tempData) : setLiveData(tempData);
} catch (e) { } catch (e) {
if (e instanceof Error) setError(`${e.name}: ${e.message}`); if (e instanceof Error && e.name !== "AbortError") {
setError(`${e.name}: ${e.message}`);
}
} }
setIsLoading(false); setIsLoading(false);
}; };
const throttledFetchData = useCallback(throttle(fetchData, 1000), []);
const fetchOptions = async () => { const fetchOptions = async () => {
if (!serverUrl) return; if (!serverUrl) return;
const url = getQueryOptions(serverUrl); const url = getQueryOptions(serverUrl);
@ -108,11 +105,9 @@ export const useFetchQuery = (): {
} else if (query.every(q => !q.trim())) { } else if (query.every(q => !q.trim())) {
setError(ErrorTypes.validQuery); setError(ErrorTypes.validQuery);
} else if (isValidHttpUrl(server)) { } else if (isValidHttpUrl(server)) {
const duration = (period.end - period.start) / 2; if (customStep.enable) period.step = customStep.value;
const bufferPeriod = {...period, start: period.start - duration, end: period.end + duration};
if (customStep.enable) bufferPeriod.step = customStep.value;
return query.filter(q => q.trim()).map(q => displayType === "chart" return query.filter(q => q.trim()).map(q => displayType === "chart"
? getQueryRangeUrl(server, q, bufferPeriod, nocache) ? getQueryRangeUrl(server, q, period, nocache)
: getQueryUrl(server, q, period)); : getQueryUrl(server, q, period));
} else { } else {
setError(ErrorTypes.validServer); setError(ErrorTypes.validServer);
@ -124,18 +119,17 @@ export const useFetchQuery = (): {
fetchOptions(); fetchOptions();
}, [serverUrl]); }, [serverUrl]);
useEffect(() => {
setPrevPeriod(undefined);
}, [query]);
// TODO: this should depend on query as well, but need to decide when to do the request. Doing it on each query change - looks to be a bad idea. Probably can be done on blur // TODO: this should depend on query as well, but need to decide when to do the request. Doing it on each query change - looks to be a bad idea. Probably can be done on blur
useEffect(() => { useEffect(() => {
fetchData(); throttledFetchData(fetchUrl);
}, [serverUrl, displayType, customStep]); }, [fetchUrl]);
useEffect(() => { useEffect(() => {
if (needUpdateData) fetchData(); const fetchPast = fetchQueue.slice(0, -1);
}, [period]); if (!fetchPast.length) return;
fetchPast.map(f => f.abort());
setFetchQueue(fetchQueue.filter(f => !f.signal.aborted));
}, [fetchQueue]);
return { fetchUrl, isLoading, graphData, liveData, error, queryOptions: queryOptions }; return { fetchUrl, isLoading, graphData, liveData, error, queryOptions: queryOptions };
}; };

View File

@ -32,6 +32,7 @@ sort: 15
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): add `stale_samples_over_time(m[d])` function for calculating the number of [staleness marks](https://docs.victoriametrics.com/vmagent.html#prometheus-staleness-markers) for time series `m` over the duration `d`. This function may be useful for detecting flapping metrics at scrape targets, which periodically disappear and then appear again. * FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): add `stale_samples_over_time(m[d])` function for calculating the number of [staleness marks](https://docs.victoriametrics.com/vmagent.html#prometheus-staleness-markers) for time series `m` over the duration `d`. This function may be useful for detecting flapping metrics at scrape targets, which periodically disappear and then appear again.
* FEATURE: [vmgateway](https://docs.victoriametrics.com/vmgateway.html): add support for `extra_filters` option. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1863). * FEATURE: [vmgateway](https://docs.victoriametrics.com/vmgateway.html): add support for `extra_filters` option. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1863).
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): improve UX according to [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1960). Thanks to @Loori-R . * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): improve UX according to [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1960). Thanks to @Loori-R .
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): limit the number of requests sent to VictoriaMetrics during zooming / scrolling. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2064).
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): make sure that `vmagent` replicas scrape the same targets at different time offsets when [replication is enabled in vmagent clustering mode](https://docs.victoriametrics.com/vmagent.html#scraping-big-number-of-targets). This guarantees that the [deduplication](https://docs.victoriametrics.com/#deduplication) consistently leaves samples from the same `vmagent` replica. * BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): make sure that `vmagent` replicas scrape the same targets at different time offsets when [replication is enabled in vmagent clustering mode](https://docs.victoriametrics.com/vmagent.html#scraping-big-number-of-targets). This guarantees that the [deduplication](https://docs.victoriametrics.com/#deduplication) consistently leaves samples from the same `vmagent` replica.
* BUGFIX: return the proper response stub from `/api/v1/query_exemplars` handler, which is needed for Grafana v8+. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1999). * BUGFIX: return the proper response stub from `/api/v1/query_exemplars` handler, which is needed for Grafana v8+. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1999).