Unverified Commit 11b97adb authored by xiaoguaiguai's avatar xiaoguaiguai Committed by GitHub

add job CheckPoint History for Recovery of CheckPoint (#665)

parent db71177f
...@@ -25,6 +25,9 @@ export function parseNumStr(num: number) { ...@@ -25,6 +25,9 @@ export function parseNumStr(num: number) {
} }
export function parseMilliSecondStr(second_time: number) { export function parseMilliSecondStr(second_time: number) {
if(((second_time/1000) %60) < 1){
return second_time + "毫秒";
}
return parseSecondStr(second_time/1000); return parseSecondStr(second_time/1000);
} }
......
import {Descriptions, Empty, Tabs, Tag} from 'antd'; import {Button, Descriptions, Empty, Modal, Tabs, Tag} from 'antd';
import { import {
CheckCircleOutlined, CheckCircleOutlined,
CloseCircleOutlined, CloseCircleOutlined,
ExclamationCircleOutlined, ExclamationCircleOutlined,
MinusCircleOutlined,
RocketOutlined, RocketOutlined,
SyncOutlined SyncOutlined
} from "@ant-design/icons"; } from "@ant-design/icons";
import {parseByteStr, parseMilliSecondStr, parseSecondStr} from "@/components/Common/function"; import {parseByteStr, parseMilliSecondStr, parseSecondStr} from "@/components/Common/function";
import ProTable, {ActionType, ProColumns} from "@ant-design/pro-table";
import {useRef} from "react";
import {CheckPointsDetailInfo} from "@/pages/DevOps/data";
const {TabPane} = Tabs; const {TabPane} = Tabs;
const CheckPoints = (props: any) => { const CheckPoints = (props: any) => {
const {job} = props; const {job} = props;
const actionRef = useRef<ActionType>();
const getOverview = () => { const getOverview = () => {
return ( return (
<> <>
{(job?.jobHistory?.checkpoints) ? {(job?.jobHistory?.checkpoints) ?
<Descriptions bordered size="small" column={1} > <Descriptions bordered size="small" column={1}>
<Descriptions.Item label="CheckPoint Counts"> <Descriptions.Item label="CheckPoint Counts">
<Tag color="blue" title={"Total"}> <Tag color="blue" title={"Total"}>
<RocketOutlined/> Total: {job?.jobHistory?.checkpoints['counts']['total']} <RocketOutlined/> Total: {job?.jobHistory?.checkpoints['counts']['total']}
</Tag> </Tag>
<Tag color="red" title={"Failed"}> <Tag color="red" title={"Failed"}>
<CloseCircleOutlined /> Failed: {job?.jobHistory?.checkpoints['counts']['failed']} <CloseCircleOutlined/> Failed: {job?.jobHistory?.checkpoints['counts']['failed']}
</Tag> </Tag>
<Tag color="cyan" title={"Restored"}> <Tag color="cyan" title={"Restored"}>
<ExclamationCircleOutlined /> Restored: {job?.jobHistory?.checkpoints['counts']['restored']} <ExclamationCircleOutlined/> Restored: {job?.jobHistory?.checkpoints['counts']['restored']}
</Tag> </Tag>
<Tag color="green" title={"Completed"}> <Tag color="green" title={"Completed"}>
<CheckCircleOutlined /> Completed: {job?.jobHistory?.checkpoints['counts']['completed']} <CheckCircleOutlined/> Completed: {job?.jobHistory?.checkpoints['counts']['completed']}
</Tag> </Tag>
<Tag color="orange" title={"In Progress"}> <Tag color="orange" title={"In Progress"}>
<SyncOutlined /> In Progress: {job?.jobHistory?.checkpoints['counts']['in_progress']} <SyncOutlined spin/> In Progress: {job?.jobHistory?.checkpoints['counts']['in_progress']}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
...@@ -47,7 +51,7 @@ const CheckPoints = (props: any) => { ...@@ -47,7 +51,7 @@ const CheckPoints = (props: any) => {
<Descriptions.Item label="Latest Failed CheckPoint"> <Descriptions.Item label="Latest Failed CheckPoint">
<Tag color="red" title={"Latest Failed CheckPoint"}> <Tag color="red" title={"Latest Failed CheckPoint"}>
{job?.jobHistory?.checkpoints['latest']['failed']=== null ? 'None' : {job?.jobHistory?.checkpoints['latest']['failed'] === null ? 'None' :
job?.jobHistory?.checkpoints['latest']['failed']['external_path'] job?.jobHistory?.checkpoints['latest']['failed']['external_path']
} }
</Tag> </Tag>
...@@ -56,7 +60,7 @@ const CheckPoints = (props: any) => { ...@@ -56,7 +60,7 @@ const CheckPoints = (props: any) => {
<Descriptions.Item label="Latest Restored"> <Descriptions.Item label="Latest Restored">
<Tag color="cyan" title={"Latest Restored"}> <Tag color="cyan" title={"Latest Restored"}>
{job?.jobHistory?.checkpoints['latest']['restored'] === null ? 'None' : {job?.jobHistory?.checkpoints['latest']['restored'] === null ? 'None' :
job?.jobHistory?.checkpoints['latest']['restored']['external_path'] } job?.jobHistory?.checkpoints['latest']['restored']['external_path']}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
...@@ -81,67 +85,67 @@ const CheckPoints = (props: any) => { ...@@ -81,67 +85,67 @@ const CheckPoints = (props: any) => {
return ( return (
<> <>
{(job?.jobHistory?.checkpoints) ? {(job?.jobHistory?.checkpoints) ?
<Descriptions bordered size="small" column={1} > <Descriptions bordered size="small" column={1}>
<Descriptions.Item label="End to End Duration"> <Descriptions.Item label="End to End Duration">
<Tag color="blue" title={"Max"}> <Tag color="blue" title={"Max"}>
<RocketOutlined/> Max: {parseSecondStr(job?.jobHistory?.checkpoints['summary']['end_to_end_duration']['max']) } <RocketOutlined/> Max: {parseSecondStr(job?.jobHistory?.checkpoints['summary']['end_to_end_duration']['max'])}
</Tag> </Tag>
<Tag color="green" title={"Min"}> <Tag color="green" title={"Min"}>
<RocketOutlined/> Min: {parseSecondStr(job?.jobHistory?.checkpoints['summary']['end_to_end_duration']['min']) } <RocketOutlined/> Min: {parseSecondStr(job?.jobHistory?.checkpoints['summary']['end_to_end_duration']['min'])}
</Tag> </Tag>
<Tag color="orange" title={"Avg"}> <Tag color="orange" title={"Avg"}>
<RocketOutlined/> Avg: {parseSecondStr(job?.jobHistory?.checkpoints['summary']['end_to_end_duration']['avg']) } <RocketOutlined/> Avg: {parseSecondStr(job?.jobHistory?.checkpoints['summary']['end_to_end_duration']['avg'])}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="Checkpointed Data Size"> <Descriptions.Item label="Checkpointed Data Size">
<Tag color="blue" title={"Max"}> <Tag color="blue" title={"Max"}>
<RocketOutlined/> Max: {parseByteStr(job?.jobHistory?.checkpoints['summary']['state_size']['max']) } <RocketOutlined/> Max: {parseByteStr(job?.jobHistory?.checkpoints['summary']['state_size']['max'])}
</Tag> </Tag>
<Tag color="green" title={"Min"}> <Tag color="green" title={"Min"}>
<RocketOutlined/> Min: {parseByteStr(job?.jobHistory?.checkpoints['summary']['state_size']['min']) } <RocketOutlined/> Min: {parseByteStr(job?.jobHistory?.checkpoints['summary']['state_size']['min'])}
</Tag> </Tag>
<Tag color="orange" title={"Avg"}> <Tag color="orange" title={"Avg"}>
<RocketOutlined/> Avg: {parseByteStr(job?.jobHistory?.checkpoints['summary']['state_size']['avg']) } <RocketOutlined/> Avg: {parseByteStr(job?.jobHistory?.checkpoints['summary']['state_size']['avg'])}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="Processed (persisted) in-flight data"> <Descriptions.Item label="Processed (persisted) in-flight data">
<Tag color="blue" title={"Max"}> <Tag color="blue" title={"Max"}>
<RocketOutlined/> Max: {job?.jobHistory?.checkpoints['summary']['processed_data']['max']} <RocketOutlined/> Max: {job?.jobHistory?.checkpoints['summary']['processed_data']['max']}
</Tag> </Tag>
<Tag color="green" title={"Min"}> <Tag color="green" title={"Min"}>
<RocketOutlined/> Min: {job?.jobHistory?.checkpoints['summary']['processed_data']['min']} <RocketOutlined/> Min: {job?.jobHistory?.checkpoints['summary']['processed_data']['min']}
</Tag> </Tag>
<Tag color="orange" title={"Avg"}> <Tag color="orange" title={"Avg"}>
<RocketOutlined/> Avg: {job?.jobHistory?.checkpoints['summary']['processed_data']['avg']} <RocketOutlined/> Avg: {job?.jobHistory?.checkpoints['summary']['processed_data']['avg']}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="Persisted data"> <Descriptions.Item label="Persisted data">
<Tag color="blue" title={"Max"}> <Tag color="blue" title={"Max"}>
<RocketOutlined/> Max: {job?.jobHistory?.checkpoints['summary']['persisted_data']['max']} <RocketOutlined/> Max: {job?.jobHistory?.checkpoints['summary']['persisted_data']['max']}
</Tag> </Tag>
<Tag color="green" title={"Min"}> <Tag color="green" title={"Min"}>
<RocketOutlined/> Min: {job?.jobHistory?.checkpoints['summary']['persisted_data']['min']} <RocketOutlined/> Min: {job?.jobHistory?.checkpoints['summary']['persisted_data']['min']}
</Tag> </Tag>
<Tag color="orange" title={"Avg"}> <Tag color="orange" title={"Avg"}>
<RocketOutlined/> Avg: {job?.jobHistory?.checkpoints['summary']['persisted_data']['avg']} <RocketOutlined/> Avg: {job?.jobHistory?.checkpoints['summary']['persisted_data']['avg']}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="Alignment Buffered"> <Descriptions.Item label="Alignment Buffered">
<Tag color="blue" title={"Max"}> <Tag color="blue" title={"Max"}>
<RocketOutlined/> Max: {job?.jobHistory?.checkpoints['summary']['alignment_buffered']['max']} <RocketOutlined/> Max: {job?.jobHistory?.checkpoints['summary']['alignment_buffered']['max']}
</Tag> </Tag>
<Tag color="green" title={"Min"}> <Tag color="green" title={"Min"}>
<RocketOutlined/> Min: {job?.jobHistory?.checkpoints['summary']['alignment_buffered']['min']} <RocketOutlined/> Min: {job?.jobHistory?.checkpoints['summary']['alignment_buffered']['min']}
</Tag> </Tag>
<Tag color="orange" title={"Avg"}> <Tag color="orange" title={"Avg"}>
<RocketOutlined/> Avg: {job?.jobHistory?.checkpoints['summary']['alignment_buffered']['avg']} <RocketOutlined/> Avg: {job?.jobHistory?.checkpoints['summary']['alignment_buffered']['avg']}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}/> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}/>
} }
</> </>
...@@ -149,11 +153,126 @@ const CheckPoints = (props: any) => { ...@@ -149,11 +153,126 @@ const CheckPoints = (props: any) => {
} }
function recoveryCheckPoint(row: CheckPointsDetailInfo) {
Modal.confirm({
title: 'Recovery Of CheckPoint',
content: `确定从 CheckPoint 【${row.external_path}】恢复吗?`,
okText: '确认',
cancelText: '取消',
onOk: async () => {
// TODO: handleRecoveryCheckPoint
// await handleRecoveryCheckPoint('api/task/recoveryCheckPoint', [row]);
actionRef.current?.reload?.();
}
});
}
const getHistory = () => { const getHistory = () => {
const checkPointsList: CheckPointsDetailInfo[] = [];
job?.jobHistory?.checkpoints['history']?.forEach((entity: CheckPointsDetailInfo) => {
return checkPointsList.push({
jobID: job?.id,
historyID: job?.jobHistory.id,
id: entity.id,
status: entity.status,
end_to_end_duration: entity.end_to_end_duration,
external_path: entity.external_path,
latest_ack_timestamp: entity.latest_ack_timestamp,
state_size: entity.state_size,
trigger_timestamp: entity.trigger_timestamp,
});
}
);
const columns: ProColumns<CheckPointsDetailInfo>[] = [
{
title: 'ID',
align: 'center',
dataIndex: 'id',
},
{
title: '状态',
align: 'center',
copyable: true,
render: (dom, entity) => {
if (entity.status === 'COMPLETED') {
return <Tag icon={<CheckCircleOutlined/>} color="success">{entity.status}</Tag>
}
if (entity.status === 'IN_PROGRESS') {
return <Tag icon={<SyncOutlined spin/>} color="processing">{entity.status}</Tag>
}
if (entity.status === 'FAILED') {
return <Tag icon={<CloseCircleOutlined/>} color="error">{entity.status}</Tag>
}
return <Tag icon={<MinusCircleOutlined/>} color="default">{entity.status}</Tag>
},
},
{
title: '耗时',
align: 'center',
copyable: true,
render: (dom, entity) => {
return entity.end_to_end_duration === null ? 'None' : parseMilliSecondStr(entity.end_to_end_duration);
},
},
{
title: '存储位置',
align: 'center',
copyable: true,
dataIndex: 'external_path',
},
{
title: '最后响应时间',
align: 'center',
dataIndex: 'latest_ack_timestamp',
valueType: 'dateTime',
},
{
title: '状态大小',
align: 'center',
render: (dom, entity) => {
return entity.state_size === null ? 'None' : parseByteStr(entity.state_size);
},
},
{
title: '触发时间',
align: 'center',
valueType: 'dateTime',
dataIndex: 'trigger_timestamp',
},
{
title: '操作',
align: 'center',
render: (dom, entity) => {
return <>
{entity.status === 'COMPLETED' ?
<Button disabled title="暂不可用" onClick={() => recoveryCheckPoint(entity)}>此处恢复</Button> : undefined}
</>
},
},
];
return ( return (
<> <>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE}/> <ProTable<CheckPointsDetailInfo>
columns={columns}
style={{width: '100%'}}
dataSource={checkPointsList}
onDataSourceChange={(dataSource) => {
actionRef.current?.reload();
}}
actionRef={actionRef}
rowKey="id"
pagination={{
pageSize: 10,
}}
toolBarRender={false}
dateFormatter="string"
search={false}
size="small"
/>
</> </>
) )
} }
...@@ -164,76 +283,76 @@ const CheckPoints = (props: any) => { ...@@ -164,76 +283,76 @@ const CheckPoints = (props: any) => {
return ( return (
<> <>
{(job?.jobHistory?.checkpointsConfig) ? {(job?.jobHistory?.checkpointsConfig) ?
<Descriptions bordered size="small" column={1} > <Descriptions bordered size="small" column={1}>
<Descriptions.Item label="Checkpointing Mode"> <Descriptions.Item label="Checkpointing Mode">
<Tag color="blue" title={"Checkpointing Mode"}> <Tag color="blue" title={"Checkpointing Mode"}>
{job?.jobHistory?.checkpointsConfig['mode'].toUpperCase() } {job?.jobHistory?.checkpointsConfig['mode'].toUpperCase()}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="Checkpoint Storage"> <Descriptions.Item label="Checkpoint Storage">
<Tag color="blue" title={"Checkpoint Storage"}> <Tag color="blue" title={"Checkpoint Storage"}>
{job?.jobHistory?.checkpointsConfig['checkpoint_storage']? job?.jobHistory?.checkpointsConfig['checkpoint_storage'] : 'Disabled'} {job?.jobHistory?.checkpointsConfig['checkpoint_storage'] ? job?.jobHistory?.checkpointsConfig['checkpoint_storage'] : 'Disabled'}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="State Backend"> <Descriptions.Item label="State Backend">
<Tag color="blue" title={"State Backend"}> <Tag color="blue" title={"State Backend"}>
{job?.jobHistory?.checkpointsConfig['state_backend'] ? job?.jobHistory?.checkpointsConfig['state_backend'] : 'Disabled' } {job?.jobHistory?.checkpointsConfig['state_backend'] ? job?.jobHistory?.checkpointsConfig['state_backend'] : 'Disabled'}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="Interval"> <Descriptions.Item label="Interval">
<Tag color="blue" title={"Interval"}> <Tag color="blue" title={"Interval"}>
{job?.jobHistory?.checkpointsConfig['interval'] } {job?.jobHistory?.checkpointsConfig['interval']}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="Timeout"> <Descriptions.Item label="Timeout">
<Tag color="blue" title={"Timeout"}> <Tag color="blue" title={"Timeout"}>
{parseMilliSecondStr(job?.jobHistory?.checkpointsConfig['timeout'])} {(job?.jobHistory?.checkpointsConfig['timeout'])}
</Tag>
</Descriptions.Item>
<Descriptions.Item label="Minimum Pause Between Checkpoints">
<Tag color="blue" title={"Minimum Pause Between Checkpoints"}>
{parseSecondStr(job?.jobHistory?.checkpointsConfig['min_pause']) }
</Tag>
</Descriptions.Item>
<Descriptions.Item label="Maximum Concurrent Checkpoints">
<Tag color="blue" title={"Maximum Concurrent Checkpoints"}>
{job?.jobHistory?.checkpointsConfig['max_concurrent'] }
</Tag>
</Descriptions.Item>
<Descriptions.Item label="Unaligned Checkpoints ">
<Tag color="blue" title={"Unaligned Checkpoints"}>
{job?.jobHistory?.checkpointsConfig['unaligned_checkpoints'] ? 'Enabled' : 'Disabled'}
</Tag>
</Descriptions.Item>
<Descriptions.Item label="Persist Checkpoints Externally Enabled">
<Tag color="blue" title={"Persist Checkpoints Externally Enabled"}>
{job?.jobHistory?.checkpointsConfig['externalization']['enabled'] ? 'Enabled' : 'Disabled'}
</Tag>
</Descriptions.Item>
{job?.jobHistory?.checkpointsConfig['externalization']['enabled'] && (
<Descriptions.Item label="Delete On Cancellation">
<Tag color="blue" title={"Delete On Cancellation"}>
{job?.jobHistory?.checkpointsConfig['externalization']['delete_on_cancellation'] ? 'Enabled' : 'Disabled'}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
)}
<Descriptions.Item label="Minimum Pause Between Checkpoints">
<Tag color="blue" title={"Minimum Pause Between Checkpoints"}>
{(job?.jobHistory?.checkpointsConfig['min_pause'])}
</Tag>
</Descriptions.Item>
<Descriptions.Item label="Maximum Concurrent Checkpoints">
<Tag color="blue" title={"Maximum Concurrent Checkpoints"}>
{job?.jobHistory?.checkpointsConfig['max_concurrent']}
</Tag>
</Descriptions.Item>
<Descriptions.Item label="Unaligned Checkpoints ">
<Tag color="blue" title={"Unaligned Checkpoints"}>
{job?.jobHistory?.checkpointsConfig['unaligned_checkpoints'] ? 'Enabled' : 'Disabled'}
</Tag>
</Descriptions.Item>
<Descriptions.Item label="Tolerable Failed Checkpoints"> <Descriptions.Item label="Persist Checkpoints Externally Enabled">
<Tag color="blue" title={"Tolerable Failed Checkpoints"}> <Tag color="blue" title={"Persist Checkpoints Externally Enabled"}>
{job?.jobHistory?.checkpointsConfig['tolerable_failed_checkpoints'] } {job?.jobHistory?.checkpointsConfig['externalization']['enabled'] ? 'Enabled' : 'Disabled'}
</Tag> </Tag>
</Descriptions.Item> </Descriptions.Item>
</Descriptions> {job?.jobHistory?.checkpointsConfig['externalization']['enabled'] && (
: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}/> <Descriptions.Item label="Delete On Cancellation">
<Tag color="blue" title={"Delete On Cancellation"}>
{job?.jobHistory?.checkpointsConfig['externalization']['delete_on_cancellation'] ? 'Enabled' : 'Disabled'}
</Tag>
</Descriptions.Item>
)}
<Descriptions.Item label="Tolerable Failed Checkpoints">
<Tag color="blue" title={"Tolerable Failed Checkpoints"}>
{job?.jobHistory?.checkpointsConfig['tolerable_failed_checkpoints']}
</Tag>
</Descriptions.Item>
</Descriptions>
: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}/>
} }
</> </>
) )
......
...@@ -114,3 +114,14 @@ export type TaskContainerConfigInfo = { ...@@ -114,3 +114,14 @@ export type TaskContainerConfigInfo = {
} }
export type CheckPointsDetailInfo = {
jobID: number,
historyID: number,
id: number,
status: string,
end_to_end_duration: number,
external_path : string,
latest_ack_timestamp: number,
state_size: number,
trigger_timestamp: number,
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment