Skip to content

Commit 9e98f40

Browse files
fix: write intelligent timing to query (#2853)
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
1 parent 2e6adf9 commit 9e98f40

File tree

2 files changed

+75
-31
lines changed

2 files changed

+75
-31
lines changed

src/components/QueryExecutionStatus/QueryExecutionStatus.tsx

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {HOUR_IN_SECONDS, SECOND_IN_MS} from '../../utils/constants';
1212
import {useTypedSelector} from '../../utils/hooks';
1313
import {isAxiosError} from '../../utils/response';
1414

15+
import {useElapsedDuration} from './useElapsedDuration';
16+
1517
import './QueryExecutionStatus.scss';
1618

1719
const b = cn('kv-query-execution-status');
@@ -29,38 +31,17 @@ export const QueryExecutionStatus = ({className, error, loading}: QueryExecution
2931
let textColor: TextProps['color'];
3032
const {startTime, endTime} = useTypedSelector(selectQueryDuration);
3133

32-
const [queryDuration, setQueryDuration] = React.useState<number>(
33-
startTime ? (endTime || Date.now()) - startTime : 0,
34-
);
35-
36-
const isCancelled = isQueryCancelledError(error);
37-
38-
const setDuration = React.useCallback(() => {
39-
if (startTime) {
40-
const actualEndTime = endTime || Date.now();
41-
setQueryDuration(actualEndTime - startTime);
34+
const durationMs = useElapsedDuration({startTime, endTime, loading});
35+
const formattedDuration = React.useMemo(() => {
36+
if (durationMs < 10 * SECOND_IN_MS) {
37+
return duration(durationMs).format('mm:ss.SSS');
4238
}
43-
}, [endTime, startTime]);
39+
return durationMs > HOUR_IN_SECONDS * SECOND_IN_MS
40+
? duration(durationMs).format('hh:mm:ss')
41+
: duration(durationMs).format('mm:ss');
42+
}, [durationMs]);
4443

45-
React.useEffect(() => {
46-
let timerId: ReturnType<typeof setInterval> | undefined;
47-
setDuration();
48-
49-
if (loading) {
50-
timerId = setInterval(setDuration, SECOND_IN_MS);
51-
} else {
52-
clearInterval(timerId);
53-
}
54-
return () => {
55-
clearInterval(timerId);
56-
};
57-
}, [loading, setDuration]);
58-
59-
const formattedQueryDuration = React.useMemo(() => {
60-
return queryDuration > HOUR_IN_SECONDS * SECOND_IN_MS
61-
? duration(queryDuration).format('hh:mm:ss')
62-
: duration(queryDuration).format('mm:ss');
63-
}, [queryDuration]);
44+
const isCancelled = isQueryCancelledError(error);
6445

6546
if (loading) {
6647
theme = 'info';
@@ -96,7 +77,7 @@ export const QueryExecutionStatus = ({className, error, loading}: QueryExecution
9677
size="m"
9778
className={b(null, className)}
9879
icon={icon}
99-
value={formattedQueryDuration}
80+
value={formattedDuration}
10081
>
10182
<Text color={textColor}>{label}</Text>
10283
</Label>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React from 'react';
2+
3+
import {SECOND_IN_MS} from '../../utils/constants';
4+
5+
const FAST_REFRESH_MS = 100;
6+
const FAST_REFRESH_JITTER_MS = 20;
7+
const TEN_SECONDS_IN_MS = 10 * SECOND_IN_MS;
8+
9+
interface UseElapsedDurationParams {
10+
startTime?: number;
11+
endTime?: number;
12+
loading?: boolean;
13+
}
14+
15+
export function useElapsedDuration({
16+
startTime,
17+
endTime,
18+
loading,
19+
}: UseElapsedDurationParams): number {
20+
const [durationMs, setDurationMs] = React.useState<number>(
21+
startTime ? (endTime || Date.now()) - startTime : 0,
22+
);
23+
24+
const setDuration = React.useCallback(() => {
25+
if (startTime) {
26+
const actualEndTime = endTime || Date.now();
27+
setDurationMs(actualEndTime - startTime);
28+
}
29+
}, [endTime, startTime]);
30+
31+
const timerRef = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
32+
const cancelledRef = React.useRef<boolean>(false);
33+
34+
const tick = React.useCallback(() => {
35+
if (cancelledRef.current) {
36+
return;
37+
}
38+
setDuration();
39+
40+
if (!loading || !startTime) {
41+
return;
42+
}
43+
44+
const actualEndTime = endTime || Date.now();
45+
const elapsedMs = actualEndTime - startTime;
46+
const jitter = Math.floor((Math.random() * 2 - 1) * FAST_REFRESH_JITTER_MS);
47+
const nextDelay = elapsedMs < TEN_SECONDS_IN_MS ? FAST_REFRESH_MS + jitter : SECOND_IN_MS;
48+
timerRef.current = setTimeout(tick, nextDelay);
49+
}, [setDuration, loading, startTime, endTime]);
50+
51+
React.useEffect(() => {
52+
cancelledRef.current = false;
53+
tick();
54+
return () => {
55+
cancelledRef.current = true;
56+
if (timerRef.current) {
57+
clearTimeout(timerRef.current);
58+
}
59+
};
60+
}, [tick]);
61+
62+
return durationMs;
63+
}

0 commit comments

Comments
 (0)