From b4f69a4e2e585e9e06f26e4ba6e4bf3de8a4fa60 Mon Sep 17 00:00:00 2001 From: jialin Date: Fri, 16 Jan 2026 16:24:43 +0800 Subject: [PATCH] perf: cancel the request when leaving page --- src/hooks/use-table-fetch.ts | 27 +++++++++----- src/pages/cluster-management/apis/index.ts | 10 ++++-- .../components/add-worker/index.tsx | 17 +++++++-- .../components/add-worker/select-cluster.tsx | 14 ++++++-- .../hooks/use-add-worker-message.ts | 1 + src/pages/llmodels/hooks/index.ts | 35 ++++--------------- 6 files changed, 60 insertions(+), 44 deletions(-) diff --git a/src/hooks/use-table-fetch.ts b/src/hooks/use-table-fetch.ts index f9df993d..3cbc74ba 100644 --- a/src/hooks/use-table-fetch.ts +++ b/src/hooks/use-table-fetch.ts @@ -58,11 +58,12 @@ export default function useTableFetch( updateManually } = options; const pollingRef = useRef(null); - const chunkRequedtRef = useRef(null); + const chunkRequestRef = useRef(null); const modalRef = useRef(null); const rowSelection = useTableRowSelection(); const { sortOrder, handleMultiSortChange } = useTableMultiSort(); const axiosTokenRef = useRef(null); + const timerIDRef = useRef(null); // ======= to resolve worker upate issue ======= const shouldUpdateRef = useRef(false); @@ -238,16 +239,16 @@ export default function useTableFetch( // ============================================ }; - const createModelsChunkRequest = async (params?: any) => { + const createTableListChunkRequest = async (params?: any) => { if (!API || !watch) return; shouldUpdateRef.current = false; - chunkRequedtRef.current?.current?.cancel?.(); + chunkRequestRef.current?.current?.cancel?.(); try { const currentParams = params || queryParams; const query = _.omit(currentParams, ['page', 'perPage']); - chunkRequedtRef.current = setChunkRequest({ + chunkRequestRef.current = setChunkRequest({ url: `${API}?${qs.stringify(_.pickBy(query, (val: any) => !!val))}`, handler: updateHandler }); @@ -286,7 +287,7 @@ export default function useTableFetch( setQueryParams(newQueryParams); await fetchData({ query: newQueryParams }); if (watch && !options?.paginate) { - createModelsChunkRequest(newQueryParams); + createTableListChunkRequest(newQueryParams); } }; @@ -338,7 +339,6 @@ export default function useTableFetch( name: row.name, ...options, async onOk() { - console.log('OK'); await deleteAPI?.(row.id, { ...modalRef.current?.configuration }); @@ -398,15 +398,24 @@ export default function useTableFetch( }, [dataSource.loadend, queryParams]); useEffect(() => { + let mounted = true; + const init = async () => { await fetchData(); - setTimeout(() => { - createModelsChunkRequest(); + + timerIDRef.current = setTimeout(() => { + if (mounted) { + createTableListChunkRequest(); + } }, 200); }; + init(); + return () => { - chunkRequedtRef.current?.cancel?.(); + mounted = false; + clearTimeout(timerIDRef.current); + chunkRequestRef.current?.current?.cancel?.(); axiosTokenRef.current?.cancel?.(); cacheDataListRef.current = []; }; diff --git a/src/pages/cluster-management/apis/index.ts b/src/pages/cluster-management/apis/index.ts index 39317f9b..9c26838c 100644 --- a/src/pages/cluster-management/apis/index.ts +++ b/src/pages/cluster-management/apis/index.ts @@ -156,9 +156,15 @@ export async function queryClusterItem(params: { id: number }, options?: any) { }); } -export async function queryClusterToken(params: { id: number }) { +export async function queryClusterToken( + params: { id: number }, + options?: { + token?: any; + } +) { return request(`${CLUSTERS_API}/${params.id}/${CLUSTER_TOKEN}`, { - method: 'GET' + method: 'GET', + cancelToken: options?.token }); } diff --git a/src/pages/cluster-management/components/add-worker/index.tsx b/src/pages/cluster-management/components/add-worker/index.tsx index cf48e10e..980444d8 100644 --- a/src/pages/cluster-management/components/add-worker/index.tsx +++ b/src/pages/cluster-management/components/add-worker/index.tsx @@ -1,4 +1,5 @@ import GSDrawer from '@/components/scroller-modal/gs-drawer'; +import { createAxiosToken } from '@/hooks/use-chunk-request'; import ColumnWrapper from '@/pages/_components/column-wrapper'; import useAddWorkerMessage from '@/pages/cluster-management/hooks/use-add-worker-message'; import { useIntl } from '@umijs/max'; @@ -59,8 +60,10 @@ const AddWorker: React.FC = (props) => { stepList = [] } = props || {}; const intl = useIntl(); - const { addedCount, createModelsChunkRequest } = useAddWorkerMessage(); + const { addedCount, createModelsChunkRequest, chunkRequestRef } = + useAddWorkerMessage(); const firstLoad = React.useRef(true); + const axiosTokenRef = React.useRef(null); const [registrationInfo, setRegistrationInfo] = React.useState<{ token: string; image: string; @@ -75,7 +78,12 @@ const AddWorker: React.FC = (props) => { const handleOnClusterChange = async (value: number, row?: any) => { try { - const data = await queryClusterToken({ id: value }); + axiosTokenRef.current?.cancel?.(); + axiosTokenRef.current = createAxiosToken(); + const data = await queryClusterToken( + { id: value }, + { token: axiosTokenRef.current.token } + ); firstLoad.current = false; setRegistrationInfo({ ...data, @@ -92,12 +100,17 @@ const AddWorker: React.FC = (props) => { } return () => { firstLoad.current = true; + chunkRequestRef.current?.current?.cancel?.(); + axiosTokenRef.current?.cancel?.(); }; }, [open, cluster_id]); useEffect(() => { if (open) { createModelsChunkRequest(); + } else { + chunkRequestRef.current?.current?.cancel?.(); + axiosTokenRef.current?.cancel?.(); } }, [open]); diff --git a/src/pages/cluster-management/components/add-worker/select-cluster.tsx b/src/pages/cluster-management/components/add-worker/select-cluster.tsx index d5c83e93..c266e42f 100644 --- a/src/pages/cluster-management/components/add-worker/select-cluster.tsx +++ b/src/pages/cluster-management/components/add-worker/select-cluster.tsx @@ -1,7 +1,7 @@ import BaseSelect from '@/components/seal-form/base/select'; import { useIntl } from '@umijs/max'; import { Spin, Typography } from 'antd'; -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { useAddWorkerContext } from './add-worker-context'; import { AddWorkerStepProps, StepNamesMap } from './config'; import { Title } from './constainers'; @@ -20,10 +20,17 @@ const SelectCluster: React.FC = ({ disabled }) => { } = useAddWorkerContext(); const intl = useIntl(); - const clusterId = summary.get('cluster_id'); + const [clusterId, setClusterId] = useState( + summary.get('cluster_id') + ); const stepIndex = stepList.indexOf(StepNamesMap.SelectCluster) + 1; + const handleOnClusterChange = (value: number, option: any) => { + setClusterId(value); + onClusterChange?.(value, option); + }; + useEffect(() => { const unregister = registerField('cluster_id'); return () => { @@ -34,6 +41,7 @@ const SelectCluster: React.FC = ({ disabled }) => { useEffect(() => { updateField('cluster_id', registrationInfo.cluster_id); // update cluster name in summary + setClusterId(registrationInfo.cluster_id); const selectedCluster = clusterList?.find( (item) => item.value === registrationInfo.cluster_id ); @@ -76,7 +84,7 @@ const SelectCluster: React.FC = ({ disabled }) => { defaultValue={registrationInfo.cluster_id} options={clusterList} value={clusterId} - onChange={onClusterChange} + onChange={handleOnClusterChange} style={{ width: '100%' }} /> {!clusterLoading && !clusterList?.length && ( diff --git a/src/pages/cluster-management/hooks/use-add-worker-message.ts b/src/pages/cluster-management/hooks/use-add-worker-message.ts index 803bf339..b1842d9a 100644 --- a/src/pages/cluster-management/hooks/use-add-worker-message.ts +++ b/src/pages/cluster-management/hooks/use-add-worker-message.ts @@ -64,6 +64,7 @@ export default function useAddWorkerMessage() { return { addedCount, + chunkRequestRef, createModelsChunkRequest }; } diff --git a/src/pages/llmodels/hooks/index.ts b/src/pages/llmodels/hooks/index.ts index 1cccbf93..73a58e68 100644 --- a/src/pages/llmodels/hooks/index.ts +++ b/src/pages/llmodels/hooks/index.ts @@ -240,6 +240,7 @@ export const useCheckCompatibility = () => { message: '' }; } + const { compatible, compatibility_messages = [], @@ -263,13 +264,10 @@ export const useCheckCompatibility = () => { Object.entries(resource_claim_by_cluster_id || {}) ); - // current cluster resource claim + // current cluster resource claim: {ram: number, vram: number} const resource_claim = resourceClaimMap.get(`${cluster_id}`); - const hasClaim = !!resource_claim?.ram || !!resource_claim?.vram; - - // current cluster is not available, but other clusters are available - const othersAvailable = !hasClaim && resourceClaimMap.size > 0; + const hasClaim = resourceClaimMap.has(`${cluster_id}`); let compatibilityMessage = compatibility_messages.join(' '); @@ -288,8 +286,8 @@ export const useCheckCompatibility = () => { }; if (hasClaim) { - const ram = convertFileSize(resource_claim.ram, 2); - const vram = convertFileSize(resource_claim.vram, 2); + const ram = convertFileSize(resource_claim?.ram || 0, 2); + const vram = convertFileSize(resource_claim?.vram || 0, 2); let messageId = 'models.form.check.claims'; if (!ram) { messageId = 'models.form.check.claims2'; @@ -301,30 +299,11 @@ export const useCheckCompatibility = () => { title: intl.formatMessage({ id: 'models.form.check.passed' }), message: intl.formatMessage({ id: messageId }, { ram, vram }) }; - } else if ( - othersAvailable && - !scheduling_messages?.length && - !compatibility_messages?.length - ) { - // no specific messages, but other clusters are available - msgData = { - title: intl.formatMessage({ - id: 'models.form.check.clusterUnavailable' - }), - message: intl.formatMessage( - { - id: 'models.form.check.otherClustersAvailable' - }, - { - clusters: getAvailableClusters(Array.from(resourceClaimMap.keys())) - } - ) - }; } return { - show: !compatible || hasClaim || othersAvailable, - type: !compatible || othersAvailable ? 'warning' : 'success', + show: !compatible || hasClaim, + type: !compatible ? 'warning' : 'success', ...msgData }; };