-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: show session idle checker in session detail panel
- Loading branch information
1 parent
324344b
commit 2855355
Showing
29 changed files
with
499 additions
and
48 deletions.
There are no files selected for viewing
185 changes: 185 additions & 0 deletions
185
react/src/components/ComputeSessionNodeItems/SessionIdleChecks.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
import { | ||
formatDurationAsDays, | ||
getIdleChecksTagColor, | ||
getUtilizationCheckerColor, | ||
toFixedFloorWithoutTrailingZeros, | ||
} from '../../helper'; | ||
import { useResourceSlotsDetails } from '../../hooks/backendai'; | ||
import DoubleTag from '../DoubleTag'; | ||
import Flex from '../Flex'; | ||
import { SessionIdleChecksFragment$key } from './__generated__/SessionIdleChecksFragment.graphql'; | ||
import { SessionIdleChecksNodeFragment$key } from './__generated__/SessionIdleChecksNodeFragment.graphql'; | ||
import { QuestionCircleOutlined } from '@ant-design/icons'; | ||
import { Tooltip, Typography, theme } from 'antd'; | ||
import graphql from 'babel-plugin-relay/macro'; | ||
import _ from 'lodash'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { useFragment } from 'react-relay'; | ||
|
||
type BaseExtra = any | null; | ||
type UtilizationExtra = { | ||
resources: { | ||
cpu_util: number[]; | ||
mem: number[]; | ||
cuda_util: number[]; | ||
cuda_mem: number[]; | ||
ipu_util: number[]; | ||
ipu_mem: number[]; | ||
}; | ||
thresholds_check_operator: 'and' | 'or'; | ||
}; | ||
export type IdleCheckItem = { | ||
extra: BaseExtra | UtilizationExtra; | ||
remaining: number | null; | ||
remaining_time_type: 'expire_after' | 'grace_period'; | ||
}; | ||
export type IdleChecks = { | ||
network_timeout?: IdleCheckItem; | ||
session_lifetime?: IdleCheckItem; | ||
utilization?: IdleCheckItem; | ||
}; | ||
|
||
interface SessionIdleChecksProps { | ||
sessionNodeFrgmt?: SessionIdleChecksNodeFragment$key | null; | ||
sessionFrgmt?: SessionIdleChecksFragment$key | null; | ||
direction?: 'row' | 'column'; | ||
} | ||
|
||
const SessionIdleChecks: React.FC<SessionIdleChecksProps> = ({ | ||
sessionNodeFrgmt = null, | ||
sessionFrgmt = null, | ||
direction = 'row', | ||
}) => { | ||
const { t } = useTranslation(); | ||
const { token } = theme.useToken(); | ||
const { mergedResourceSlots } = useResourceSlotsDetails(); | ||
|
||
const sessionNode = useFragment( | ||
graphql` | ||
fragment SessionIdleChecksNodeFragment on ComputeSessionNode { | ||
id | ||
idle_checks @since(version: "24.12.0") | ||
} | ||
`, | ||
sessionNodeFrgmt, | ||
); | ||
const session = useFragment( | ||
graphql` | ||
fragment SessionIdleChecksFragment on ComputeSession { | ||
id | ||
idle_checks @since(version: "24.09.0") | ||
} | ||
`, | ||
sessionFrgmt, | ||
); | ||
|
||
const idleChecks: IdleChecks = JSON.parse( | ||
sessionNode?.idle_checks || session?.idle_checks || '{}', | ||
); | ||
|
||
const getIdleCheckTitle = (key: keyof IdleChecks) => { | ||
if (key === 'network_timeout') return t('session.NetworkIdleTimeout'); | ||
else if (key === 'session_lifetime') return t('session.MaxSessionLifetime'); | ||
else return t('session.UtilizationIdleTimeout'); | ||
}; | ||
|
||
const getRemainingTimeTypeLabel = (Type: 'expire_after' | 'grace_period') => { | ||
if (Type === 'expire_after') { | ||
return t('session.ExpiresAfter'); | ||
} else { | ||
return t('session.GracePeriod'); | ||
} | ||
}; | ||
|
||
return ( | ||
<Flex direction={direction} align="stretch" gap="sm"> | ||
{_.map(idleChecks, (value: IdleCheckItem, key: keyof IdleChecks) => { | ||
if (!value.remaining) return null; | ||
|
||
return ( | ||
<Flex | ||
key={key} | ||
style={{ flex: 1 }} | ||
direction="column" | ||
align="stretch" | ||
> | ||
<Flex gap={'xxs'}> | ||
<Typography.Text>{getIdleCheckTitle(key)}</Typography.Text> | ||
{key === 'utilization' && ( | ||
<Tooltip | ||
title={ | ||
<> | ||
{`${t('session.Utilization')} / ${t('session.Threshold')} (%)`} | ||
<br /> | ||
{_.map(value.extra.resources, (resource, key) => { | ||
const deviceName = ['cpu_util', 'mem'].includes(key) | ||
? _.split(key, '_')[0] | ||
: _.split(key, '_')[0] + '.device'; | ||
const [utilization, threshold] = resource; | ||
return ( | ||
<Flex key={key} gap={'xs'}> | ||
<Typography.Text | ||
style={{ color: token.colorWhite }} | ||
>{`${mergedResourceSlots?.[deviceName]?.human_readable_name}:`}</Typography.Text> | ||
<Typography.Text | ||
style={{ | ||
color: getUtilizationCheckerColor(resource), | ||
}} | ||
> | ||
{`${utilization >= 0 ? toFixedFloorWithoutTrailingZeros(utilization, 1) : '-'} / ${threshold}`} | ||
</Typography.Text> | ||
<br /> | ||
</Flex> | ||
); | ||
})} | ||
</> | ||
} | ||
> | ||
<QuestionCircleOutlined | ||
style={{ | ||
color: token.colorTextSecondary, | ||
cursor: 'pointer', | ||
}} | ||
/> | ||
</Tooltip> | ||
)} | ||
</Flex> | ||
|
||
{value.remaining >= 0 ? ( | ||
// TODO: support real-time update by using useIntervalValue when idle_checks returns remaining time as date | ||
<DoubleTag | ||
values={[ | ||
{ | ||
label: getRemainingTimeTypeLabel(value.remaining_time_type), | ||
color: getIdleChecksTagColor( | ||
value, | ||
key === 'utilization' ? 'utilization' : 'remaining', | ||
), | ||
}, | ||
{ | ||
label: formatDurationAsDays( | ||
new Date().toISOString(), | ||
new Date( | ||
new Date().getTime() + (value.remaining || 0) * 1000, | ||
).toISOString(), | ||
), | ||
color: getIdleChecksTagColor( | ||
value, | ||
key === 'utilization' ? 'utilization' : 'remaining', | ||
), | ||
}, | ||
]} | ||
/> | ||
) : ( | ||
<Typography.Text type="danger"> | ||
{t('session.TimeoutExceeded')} | ||
</Typography.Text> | ||
)} | ||
</Flex> | ||
); | ||
})} | ||
</Flex> | ||
); | ||
}; | ||
|
||
export default SessionIdleChecks; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import BAIModal from './BAIModal'; | ||
import Flex from './Flex'; | ||
import { ModalProps, Typography, theme } from 'antd'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
interface IdleCheckDescriptionModalProps extends ModalProps {} | ||
|
||
const IdleCheckDescriptionModal: React.FC<IdleCheckDescriptionModalProps> = ({ | ||
...modalProps | ||
}) => { | ||
const { t } = useTranslation(); | ||
const { token } = theme.useToken(); | ||
|
||
return ( | ||
<BAIModal | ||
title={t('session.IdleChecks')} | ||
footer={null} | ||
width={700} | ||
{...modalProps} | ||
> | ||
<Typography.Text>{t('session.IdleChecksDesc')}</Typography.Text> | ||
|
||
<Typography.Title level={5}> | ||
{t('session.MaxSessionLifetime')} | ||
</Typography.Title> | ||
<p>{t('session.MaxSessionLifetimeDesc')}</p> | ||
|
||
<Typography.Title level={5}> | ||
{t('session.NetworkIdleTimeout')} | ||
</Typography.Title> | ||
<p>{t('session.NetworkIdleTimeoutDesc')}</p> | ||
|
||
<Typography.Title level={5}> | ||
{t('session.UtilizationIdleTimeout')} | ||
</Typography.Title> | ||
<p>{t('session.UtilizationIdleTimeoutDesc')}</p> | ||
<Flex | ||
direction="column" | ||
align="stretch" | ||
style={{ marginLeft: token.marginMD }} | ||
> | ||
<Typography.Title level={5} style={{ margin: 0 }}> | ||
{t('session.GracePeriod')} | ||
</Typography.Title> | ||
<p>{t('session.GracePeriodDesc')}</p> | ||
<Typography.Title level={5} style={{ margin: 0 }}> | ||
{t('session.UtilizationThreshold')} | ||
</Typography.Title> | ||
<p>{t('session.UtilizationThresholdDesc')}</p> | ||
</Flex> | ||
</BAIModal> | ||
); | ||
}; | ||
|
||
export default IdleCheckDescriptionModal; |
Oops, something went wrong.