Skip to content

Commit

Permalink
[Dashboard] Enable customizable refresh frequency for the Metrics page (
Browse files Browse the repository at this point in the history
#44037)

Currently, each chart on the Metrics page is continuously refreshing, which can put strain on the network and frontend. In our application with @nemo9cby @Bye-legumes, we have noticed that during periods of unstable cluster networks, there can be instances of response timeouts or loss.

Therefore, having the ability to customize the refresh frequency would be helpful.

In the proposed modification, we have set the default refresh frequency to 1 second and provided various frequency configurations, following the example of Grafana. This way, users can choose the refresh interval that best suits their needs.
  • Loading branch information
liuxsh9 authored Jun 20, 2024
1 parent 1a93852 commit 52947d7
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 9 deletions.
86 changes: 84 additions & 2 deletions dashboard/client/src/pages/metrics/Metrics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Alert,
AlertProps,
Button,
InputAdornment,
Link,
Menu,
MenuItem,
Expand All @@ -12,11 +13,13 @@ import {
import createStyles from "@mui/styles/createStyles";
import makeStyles from "@mui/styles/makeStyles";
import React, { useContext, useEffect, useState } from "react";
import { BiRefresh, BiTime } from "react-icons/bi";
import { RiExternalLinkLine } from "react-icons/ri";

import { GlobalContext } from "../../App";
import { CollapsibleSection } from "../../common/CollapsibleSection";
import { ClassNameProps } from "../../common/props";
import { HelpInfo } from "../../components/Tooltip";
import { MainNavPageInfo } from "../layout/mainNavContext";
import { MAIN_NAV_HEIGHT } from "../layout/MainNavLayout";

Expand Down Expand Up @@ -45,6 +48,20 @@ const useStyles = makeStyles((theme) =>
}),
);

export enum RefreshOptions {
OFF = "off",
FIVE_SECONDS = "5s",
TEN_SECONDS = "10s",
THIRTY_SECONDS = "30s",
ONE_MIN = "1m",
FIVE_MINS = "5m",
FIFTEEN_MINS = "15m",
THIRTY_MINS = "30m",
ONE_HOUR = "1h",
TWO_HOURS = "2h",
ONE_DAY = "1d",
}

export enum TimeRangeOptions {
FIVE_MINS = "Last 5 minutes",
THIRTY_MINS = "Last 30 minutes",
Expand All @@ -57,6 +74,20 @@ export enum TimeRangeOptions {
SEVEN_DAYS = "Last 7 days",
}

export const REFRESH_VALUE: Record<RefreshOptions, string> = {
[RefreshOptions.OFF]: "",
[RefreshOptions.FIVE_SECONDS]: "5s",
[RefreshOptions.TEN_SECONDS]: "10s",
[RefreshOptions.THIRTY_SECONDS]: "30s",
[RefreshOptions.ONE_MIN]: "1m",
[RefreshOptions.FIVE_MINS]: "5m",
[RefreshOptions.FIFTEEN_MINS]: "15m",
[RefreshOptions.THIRTY_MINS]: "30m",
[RefreshOptions.ONE_HOUR]: "1h",
[RefreshOptions.TWO_HOURS]: "2h",
[RefreshOptions.ONE_DAY]: "1d",
};

export const TIME_RANGE_TO_FROM_VALUE: Record<TimeRangeOptions, string> = {
[TimeRangeOptions.FIVE_MINS]: "now-5m",
[TimeRangeOptions.THIRTY_MINS]: "now-30m",
Expand Down Expand Up @@ -358,13 +389,25 @@ export const Metrics = () => {

const grafanaDefaultDatasource = dashboardDatasource ?? "Prometheus";

const [refreshOption, setRefreshOption] = useState<RefreshOptions>(
RefreshOptions.FIVE_SECONDS,
);

const [timeRangeOption, setTimeRangeOption] = useState<TimeRangeOptions>(
TimeRangeOptions.FIVE_MINS,
);

const [refresh, setRefresh] = useState<string | null>(null);

const [[from, to], setTimeRange] = useState<[string | null, string | null]>([
null,
null,
]);

useEffect(() => {
setRefresh(REFRESH_VALUE[refreshOption]);
}, [refreshOption]);

useEffect(() => {
const from = TIME_RANGE_TO_FROM_VALUE[timeRangeOption];
setTimeRange([from, "now"]);
Expand All @@ -377,6 +420,8 @@ export const Metrics = () => {
const toParam = to !== null ? `&to=${to}` : "";
const timeRangeParams = `${fromParam}${toParam}`;

const refreshParams = refresh ? `&refresh=${refresh}` : "";

return (
<div>
<MainNavPageInfo
Expand Down Expand Up @@ -435,19 +480,52 @@ export const Metrics = () => {
className={classes.timeRangeButton}
select
size="small"
style={{ width: 120 }}
sx={{ width: 80 }}
value={refreshOption}
onChange={({ target: { value } }) => {
setRefreshOption(value as RefreshOptions);
}}
variant="standard"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<BiRefresh style={{ fontSize: 25, paddingBottom: 5 }} />
</InputAdornment>
),
}}
>
{Object.entries(RefreshOptions).map(([key, value]) => (
<MenuItem key={key} value={value}>
{value}
</MenuItem>
))}
</TextField>
<HelpInfo>Auto-refresh interval</HelpInfo>
<TextField
className={classes.timeRangeButton}
select
size="small"
sx={{ width: 140 }}
value={timeRangeOption}
onChange={({ target: { value } }) => {
setTimeRangeOption(value as TimeRangeOptions);
}}
variant="standard"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<BiTime style={{ fontSize: 22, paddingBottom: 5 }} />
</InputAdornment>
),
}}
>
{Object.entries(TimeRangeOptions).map(([key, value]) => (
<MenuItem key={key} value={value}>
{value}
</MenuItem>
))}
</TextField>
<HelpInfo>Time range picker</HelpInfo>
</Paper>
<Alert severity="info">
Tip: You can click on the legend to focus on a specific line in the
Expand All @@ -459,6 +537,7 @@ export const Metrics = () => {
<MetricsSection
key={config.title}
metricConfig={config}
refreshParams={refreshParams}
timeRangeParams={timeRangeParams}
dashboardUid={grafanaDefaultDashboardUid}
dashboardDatasource={grafanaDefaultDatasource}
Expand All @@ -469,6 +548,7 @@ export const Metrics = () => {
<MetricsSection
key={config.title}
metricConfig={config}
refreshParams={refreshParams}
timeRangeParams={timeRangeParams}
dashboardUid={dashboardUids["data"]}
dashboardDatasource={grafanaDefaultDatasource}
Expand Down Expand Up @@ -511,13 +591,15 @@ const useMetricsSectionStyles = makeStyles((theme) =>

type MetricsSectionProps = {
metricConfig: MetricsSectionConfig;
refreshParams: string;
timeRangeParams: string;
dashboardUid: string;
dashboardDatasource: string;
};

const MetricsSection = ({
metricConfig: { title, contents },
refreshParams,
timeRangeParams,
dashboardUid,
dashboardDatasource,
Expand All @@ -538,7 +620,7 @@ const MetricsSection = ({
{contents.map(({ title, pathParams }) => {
const path =
`/d-solo/${dashboardUid}?${pathParams}` +
`&refresh${timeRangeParams}&var-SessionName=${sessionName}&var-datasource=${dashboardDatasource}`;
`&${refreshParams}${timeRangeParams}&var-SessionName=${sessionName}&var-datasource=${dashboardDatasource}`;
return (
<Paper
key={pathParams}
Expand Down
62 changes: 59 additions & 3 deletions dashboard/client/src/pages/serve/ServeDeploymentMetricsSection.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import { Box, Button, MenuItem, Paper, TextField } from "@mui/material";
import {
Box,
Button,
InputAdornment,
MenuItem,
Paper,
TextField,
} from "@mui/material";
import createStyles from "@mui/styles/createStyles";
import makeStyles from "@mui/styles/makeStyles";
import React, { useContext, useEffect, useState } from "react";
import { BiRefresh, BiTime } from "react-icons/bi";
import { RiExternalLinkLine } from "react-icons/ri";
import { GlobalContext } from "../../App";
import { CollapsibleSection } from "../../common/CollapsibleSection";
import { ClassNameProps } from "../../common/props";
import { HelpInfo } from "../../components/Tooltip";
import {
MetricConfig,
REFRESH_VALUE,
RefreshOptions,
TIME_RANGE_TO_FROM_VALUE,
TimeRangeOptions,
} from "../metrics";
Expand Down Expand Up @@ -86,13 +97,23 @@ export const ServeReplicaMetricsSection = ({
const grafanaServeDashboardUid =
dashboardUids?.serveDeployment ?? "rayServeDashboard";

const [refreshOption, setRefreshOption] = useState<RefreshOptions>(
RefreshOptions.FIVE_SECONDS,
);

const [timeRangeOption, setTimeRangeOption] = useState<TimeRangeOptions>(
TimeRangeOptions.FIVE_MINS,
);

const [refresh, setRefresh] = useState<string | null>(null);

const [[from, to], setTimeRange] = useState<[string | null, string | null]>([
null,
null,
]);
useEffect(() => {
setRefresh(REFRESH_VALUE[refreshOption]);
}, [refreshOption]);
useEffect(() => {
const from = TIME_RANGE_TO_FROM_VALUE[timeRangeOption];
setTimeRange([from, "now"]);
Expand All @@ -101,6 +122,7 @@ export const ServeReplicaMetricsSection = ({
const fromParam = from !== null ? `&from=${from}` : "";
const toParam = to !== null ? `&to=${to}` : "";
const timeRangeParams = `${fromParam}${toParam}`;
const refreshParams = refresh ? `&refresh=${refresh}` : "";

const replicaButtonUrl = useViewServeDeploymentMetricsButtonUrl(
deploymentName,
Expand All @@ -125,24 +147,58 @@ export const ServeReplicaMetricsSection = ({
className={classes.timeRangeButton}
select
size="small"
style={{ width: 120 }}
sx={{ width: 80 }}
value={refreshOption}
onChange={({ target: { value } }) => {
setRefreshOption(value as RefreshOptions);
}}
variant="standard"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<BiRefresh style={{ fontSize: 25, paddingBottom: 5 }} />
</InputAdornment>
),
}}
>
{Object.entries(RefreshOptions).map(([key, value]) => (
<MenuItem key={key} value={value}>
{value}
</MenuItem>
))}
</TextField>
<HelpInfo>Auto-refresh interval</HelpInfo>
<TextField
className={classes.timeRangeButton}
select
size="small"
style={{ width: 140 }}
value={timeRangeOption}
onChange={({ target: { value } }) => {
setTimeRangeOption(value as TimeRangeOptions);
}}
variant="standard"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<BiTime style={{ fontSize: 22, paddingBottom: 5 }} />
</InputAdornment>
),
}}
>
{Object.entries(TimeRangeOptions).map(([key, value]) => (
<MenuItem key={key} value={value}>
{value}
</MenuItem>
))}
</TextField>
<HelpInfo>Time range picker</HelpInfo>
</Box>
<div className={classes.grafanaEmbedsContainer}>
{METRICS_CONFIG.map(({ title, pathParams }) => {
const path =
`/d-solo/${grafanaServeDashboardUid}?${pathParams}` +
`&refresh${timeRangeParams}&var-Deployment=${encodeURIComponent(
`${refreshParams}${timeRangeParams}&var-Deployment=${encodeURIComponent(
deploymentName,
)}&var-Replica=${encodeURIComponent(
replicaId,
Expand Down
Loading

0 comments on commit 52947d7

Please sign in to comment.