From 3824c1fec0fbe207e5a0c9b54f2421eddc231c50 Mon Sep 17 00:00:00 2001 From: balibabu Date: Mon, 18 Nov 2024 17:23:49 +0800 Subject: [PATCH] feat: Show task_executor heartbeat #3409 (#3461) ### What problem does this PR solve? feat: Show task_executor heartbeat #3409 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- web/src/interfaces/database/user-setting.ts | 17 ++- .../user-setting/setting-system/index.tsx | 22 ++- .../setting-system/task-bar-chat.tsx | 142 ++++++++++-------- web/src/utils/date.ts | 21 ++- 4 files changed, 118 insertions(+), 84 deletions(-) diff --git a/web/src/interfaces/database/user-setting.ts b/web/src/interfaces/database/user-setting.ts index 17e59a217..67ccc69bc 100644 --- a/web/src/interfaces/database/user-setting.ts +++ b/web/src/interfaces/database/user-setting.ts @@ -22,16 +22,23 @@ export interface IUserInfo { export type TaskExecutorElapsed = Record; +export interface TaskExecutorHeartbeatItem { + boot_at: string; + current: null; + done: number; + failed: number; + lag: number; + name: string; + now: string; + pending: number; +} + export interface ISystemStatus { es: Es; storage: Storage; database: Database; redis: Redis; - task_executor: { - error?: string; - status: string; - elapsed?: TaskExecutorElapsed; - }; + task_executor_heartbeat: Record; } interface Redis { diff --git a/web/src/pages/user-setting/setting-system/index.tsx b/web/src/pages/user-setting/setting-system/index.tsx index 151a6a6b8..2deff39ac 100644 --- a/web/src/pages/user-setting/setting-system/index.tsx +++ b/web/src/pages/user-setting/setting-system/index.tsx @@ -2,7 +2,7 @@ import SvgIcon from '@/components/svg-icon'; import { useFetchSystemStatus } from '@/hooks/user-setting-hooks'; import { ISystemStatus, - TaskExecutorElapsed, + TaskExecutorHeartbeatItem, } from '@/interfaces/database/user-setting'; import { Badge, Card, Flex, Spin, Typography } from 'antd'; import classNames from 'classnames'; @@ -11,6 +11,7 @@ import upperFirst from 'lodash/upperFirst'; import { useEffect } from 'react'; import { toFixed } from '@/utils/common-util'; +import { isObject } from 'lodash'; import styles from './index.less'; import TaskBarChat from './task-bar-chat'; @@ -27,7 +28,7 @@ const TitleMap = { storage: 'Object Storage', redis: 'Redis', database: 'Database', - task_executor: 'Task Executor', + task_executor_heartbeats: 'Task Executor', }; const IconMap = { @@ -60,10 +61,13 @@ const SystemInfo = () => { type="inner" title={ - {key === 'task_executor' ? ( + {key === 'task_executor_heartbeats' ? ( ) : ( - + )} {TitleMap[key as keyof typeof TitleMap]} @@ -76,13 +80,15 @@ const SystemInfo = () => { } key={key} > - {key === 'task_executor' ? ( - info?.elapsed ? ( + {key === 'task_executor_heartbeats' ? ( + isObject(info) ? ( } > ) : ( - {info.error} + + {typeof info.error === 'string' ? info.error : ''} + ) ) : ( Object.keys(info) diff --git a/web/src/pages/user-setting/setting-system/task-bar-chat.tsx b/web/src/pages/user-setting/setting-system/task-bar-chat.tsx index 9097b8a5a..011e14577 100644 --- a/web/src/pages/user-setting/setting-system/task-bar-chat.tsx +++ b/web/src/pages/user-setting/setting-system/task-bar-chat.tsx @@ -1,57 +1,47 @@ -import { TaskExecutorElapsed } from '@/interfaces/database/user-setting'; +import { TaskExecutorHeartbeatItem } from '@/interfaces/database/user-setting'; import { Divider, Flex } from 'antd'; -import { max } from 'lodash'; import { Bar, BarChart, CartesianGrid, + Legend, + Rectangle, ResponsiveContainer, Tooltip, + XAxis, } from 'recharts'; +import { formatDate, formatTime } from '@/utils/date'; +import dayjs from 'dayjs'; +import { get } from 'lodash'; import styles from './index.less'; interface IProps { - data: TaskExecutorElapsed; + data: Record; } -const getColor = (value: number) => { - if (value > 120) { - return 'red'; - } else if (value <= 120 && value > 50) { - return '#faad14'; - } - return '#52c41a'; -}; - -const getMaxLength = (data: TaskExecutorElapsed) => { - const lengths = Object.keys(data).reduce((pre, cur) => { - pre.push(data[cur].length); - return pre; - }, []); - return max(lengths) ?? 0; -}; - -const fillEmptyElementByMaxLength = (list: any[], maxLength: number) => { - if (list.length === maxLength) { - return list; - } - return list.concat( - new Array(maxLength - list.length).fill({ - value: 0, - actualValue: 0, - fill: getColor(0), - }), - ); -}; - -const CustomTooltip = ({ active, payload }: any) => { +const CustomTooltip = ({ active, payload, ...restProps }: any) => { if (active && payload && payload.length) { + const taskExecutorHeartbeatItem: TaskExecutorHeartbeatItem = get( + payload, + '0.payload', + {}, + ); return ( -
-

{`${payload[0].payload.actualValue}`}

+
+
+ {formatDate(restProps.label)} +
+ {Object.entries(taskExecutorHeartbeatItem).map(([key, val], index) => { + return ( +
+ {`${key}: `} + + {key === 'now' || key === 'boot_at' ? formatDate(val) : val} + +
+ ); + })}
); } @@ -60,32 +50,56 @@ const CustomTooltip = ({ active, payload }: any) => { }; const TaskBarChat = ({ data }: IProps) => { - const maxLength = getMaxLength(data); - return ( - - {Object.keys(data).map((key) => { - const list = data[key].map((x) => ({ - value: x > 120 ? 120 : x, - actualValue: x, - fill: getColor(x), - })); - const nextList = fillEmptyElementByMaxLength(list, maxLength); - return ( - - ID: {key} - - - - } /> - - - - - - ); - })} - - ); + return Object.entries(data).map(([key, val]) => { + const data = val.map((x) => ({ + ...x, + now: dayjs(x.now).valueOf(), + failed: 5, + })); + const firstItem = data[0]; + const lastItem = data[data.length - 1]; + + const domain = [firstItem.now, lastItem.now]; + + return ( + +
+ ID: {key} + Lag: {lastItem.lag} + Pending: {lastItem.pending} +
+ + + formatTime(x)} + allowDataOverflow + angle={60} + padding={{ left: 20, right: 20 }} + tickMargin={20} + /> + + } /> + + } + /> + } + /> + + + +
+ ); + }); }; export default TaskBarChat; diff --git a/web/src/utils/date.ts b/web/src/utils/date.ts index 5da36dc64..5222cce97 100644 --- a/web/src/utils/date.ts +++ b/web/src/utils/date.ts @@ -1,5 +1,19 @@ import dayjs from 'dayjs'; +export function formatDate(date: any) { + if (!date) { + return ''; + } + return dayjs(date).format('DD/MM/YYYY HH:mm:ss'); +} + +export function formatTime(date: any) { + if (!date) { + return ''; + } + return dayjs(date).format('HH:mm:ss'); +} + export function today() { return formatDate(dayjs()); } @@ -11,10 +25,3 @@ export function lastDay() { export function lastWeek() { return formatDate(dayjs().subtract(1, 'weeks')); } - -export function formatDate(date: any) { - if (!date) { - return ''; - } - return dayjs(date).format('DD/MM/YYYY HH:mm:ss'); -}