This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
The following commit(s) were added to refs/heads/main by this push:
new 1421f2d ui: revert instance prefetch, wire service list to
auto-refresh ticker
1421f2d is described below
commit 1421f2d551ae2e2cd1b56abe22c63a0d0a37b24e
Author: Wu Sheng <[email protected]>
AuthorDate: Sun May 17 19:26:16 2026 +0800
ui: revert instance prefetch, wire service list to auto-refresh ticker
Per operator direction:
1. Drop the usePrefetchLayerInstances prefetch added in 09f996b.
It pre-warmed instance lists for every landing service in the
background, which the operator explicitly didn't want — extra
N BFF calls on every landing, and the click-time fetch was
already fast enough once the cascade is wired correctly.
2. Service list (useLayerLanding) is the layer's in-memory cache —
stays cached aggressively (staleTime: Infinity, no window-focus
refetch). Refresh paths are explicit:
- Global auto-refresh ticker via useAutoRefreshSubscribe →
refetch on each tick (operator-controlled cadence from the
topbar).
- Manual refresh button in LayerShell → q.refetch().
No silent vue-query-driven refetch under the operator.
Service-click flow stays as-is: setSelected drops ?instance= /
?endpoint= → dependent widgets reset to "Reading data…" → instance
query refires → auto-pick → dashboard query → widgets land async.
Each downstream control listens to its upstream and resets +
shows loading words before its own query fires, matching the
cascade-clear-then-load principle.
---
apps/ui/src/layer/useLayerInstances.ts | 51 ++--------------------
apps/ui/src/layer/useLayerLanding.ts | 18 +++++---
.../render/layer-dashboard/LayerDashboardsView.vue | 13 +-----
3 files changed, 15 insertions(+), 67 deletions(-)
diff --git a/apps/ui/src/layer/useLayerInstances.ts
b/apps/ui/src/layer/useLayerInstances.ts
index 7238b19..2f7977a 100644
--- a/apps/ui/src/layer/useLayerInstances.ts
+++ b/apps/ui/src/layer/useLayerInstances.ts
@@ -22,18 +22,16 @@
* BFF would reject as `missing_service`.
*/
-import { computed, watch, type Ref } from 'vue';
-import { useQuery, useQueryClient } from '@tanstack/vue-query';
+import { computed, type Ref } from 'vue';
+import { useQuery } from '@tanstack/vue-query';
import { bffClient } from '@/api/client';
-const INSTANCES_STALE_MS = 60_000;
-
export function useLayerInstances(layerKey: Ref<string>, service: Ref<string |
null>) {
const q = useQuery({
queryKey: ['layer-instances', layerKey, service],
queryFn: () => bffClient.layer.instances(layerKey.value, service.value ??
''),
enabled: computed(() => layerKey.value.length > 0 && !!service.value),
- staleTime: INSTANCES_STALE_MS,
+ staleTime: 30_000,
});
return {
data: computed(() => q.data.value ?? null),
@@ -43,46 +41,3 @@ export function useLayerInstances(layerKey: Ref<string>,
service: Ref<string | n
error: q.error,
};
}
-
-/**
- * Background pre-fetch of instance lists for every service in the
- * supplied list. Run after the landing rows arrive so the operator's
- * very next service-switch click finds the new service's instance
- * list already in cache — eliminating the ~100-500ms BFF round-trip
- * that otherwise gates the dashboard refire.
- *
- * Uses vue-query's `prefetchQuery` so each fetch goes through the
- * SAME cache key as `useLayerInstances`. The active picker call
- * then hits the cache instantly with no duplicate request. Skips
- * services we already have cached + not stale.
- *
- * Idempotent (queryClient.prefetchQuery dedups in-flight requests
- * by key) and tied to the calling scope's watch so it re-runs when
- * the layer or service list changes (e.g. when the operator
- * navigates to a different layer or hits the refresh button).
- */
-export function usePrefetchLayerInstances(
- layerKey: Ref<string>,
- serviceIds: Ref<ReadonlyArray<string>>,
-): void {
- const qc = useQueryClient();
- watch(
- [layerKey, serviceIds],
- ([key, ids]) => {
- if (!key) return;
- for (const id of ids) {
- if (!id) continue;
- // Plain values in the key — vue-query serialises refs by
- // their resolved .value, so this hashes to the same slot as
- // the active `useLayerInstances` queryKey for the same
- // (layerKey, id) pair.
- void qc.prefetchQuery({
- queryKey: ['layer-instances', key, id],
- queryFn: () => bffClient.layer.instances(key, id),
- staleTime: INSTANCES_STALE_MS,
- });
- }
- },
- { immediate: true },
- );
-}
diff --git a/apps/ui/src/layer/useLayerLanding.ts
b/apps/ui/src/layer/useLayerLanding.ts
index 52bfa1a..246b21e 100644
--- a/apps/ui/src/layer/useLayerLanding.ts
+++ b/apps/ui/src/layer/useLayerLanding.ts
@@ -17,6 +17,7 @@
import { computed, type Ref } from 'vue';
import { useQuery } from '@tanstack/vue-query';
+import { useAutoRefreshSubscribe } from '../controls/useAutoRefreshSubscribe';
import type { LandingConfig, LandingResponse, LayerDef } from
'@skywalking-horizon-ui/api-client';
import { bffClient } from '@/api/client';
@@ -61,13 +62,14 @@ export function useLayerLanding(
return `${r.step}:${Math.floor(r.startMs / 60_000)}:${Math.floor(r.endMs /
60_000)}`;
});
- // Service list is fetched ONCE per (layer, cfg, range) and stays
- // cached. No `refetchInterval`, no `refetchOnWindowFocus`, not
- // wired into the global auto-refresh ticker: the operator-facing
- // contract is "service list doesn't move under you". Manual
- // refresh is the `q.refetch()` handle exposed below — wired to
- // a refresh button in LayerShell so operators can pull a fresh
- // list on demand.
+ // Service list is the layer's in-memory snapshot — cache it
+ // aggressively (staleTime: Infinity, no window-focus refetch).
+ // Two ways to refresh:
+ // 1. The global auto-refresh ticker (`useAutoRefreshSubscribe`
+ // below) — operator pace, controlled from the topbar.
+ // 2. The manual refresh button in LayerShell — `q.refetch()`.
+ // No silent vue-query-driven refetch under the operator, so the
+ // service list never moves on its own between operator actions.
const q = useQuery({
queryKey: ['layer-landing', layerKey, cfgHash, rangeKey],
queryFn: () =>
@@ -81,6 +83,8 @@ export function useLayerLanding(
retry: 1,
});
+ useAutoRefreshSubscribe(() => q.refetch());
+
const data = computed<LandingResponse | null>(() => q.data.value ?? null);
const rows = computed(() => data.value?.rows ?? []);
const reachable = computed(() => data.value?.reachable ?? false);
diff --git a/apps/ui/src/render/layer-dashboard/LayerDashboardsView.vue
b/apps/ui/src/render/layer-dashboard/LayerDashboardsView.vue
index 23e97ab..246ba7f 100644
--- a/apps/ui/src/render/layer-dashboard/LayerDashboardsView.vue
+++ b/apps/ui/src/render/layer-dashboard/LayerDashboardsView.vue
@@ -35,7 +35,7 @@ import { colorForMetric } from '@/utils/metricColor';
import { useLayerDashboard, useLayerDashboardConfig } from
'@/render/layer-dashboard/useLayerDashboard';
import { useLayerPageOrchestrator } from
'@/render/layer-dashboard/useLayerPageOrchestrator';
import { useLayerEndpoints } from '@/layer/useLayerEndpoints';
-import { useLayerInstances, usePrefetchLayerInstances } from
'@/layer/useLayerInstances';
+import { useLayerInstances } from '@/layer/useLayerInstances';
import { useLayerLanding } from '@/layer/useLayerLanding';
import { useTimeRangeStore } from '@/controls/timeRange';
import { useLayers } from '@/shell/useLayers';
@@ -148,17 +148,6 @@ const expandedInstance = ref<string | null>(null);
* bound to it. */
const { setSelected: setSelectedService } = useSelectedService();
const landingRows = computed(() => landing.data.value?.sampledRows ??
landing.rows.value ?? []);
-// Background pre-fetch — kick off instance-list requests for every
-// service in the landing as soon as rows arrive, so the operator's
-// next service-switch click finds the new service's instance list
-// already cached. Uses vue-query's prefetchQuery under the same
-// cache key as the active `useLayerInstances`, so no duplicate
-// requests fire. Eliminates the ~100-500ms BFF round-trip that
-// otherwise gates the dashboard refire on service change.
-usePrefetchLayerInstances(
- layerKey,
- computed(() => landingRows.value.map((r) => r.serviceId)),
-);
watch(landingRows, (rows) => {
const first = rows[0];
if (!first) return;