mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-26 06:04:05 -08:00
Add server readiness check and WAL replay progress display
Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
parent
8fae131733
commit
1aa79e29a2
|
@ -62,6 +62,7 @@ import { Notifications } from "@mantine/notifications";
|
||||||
import { useAppDispatch } from "./state/hooks";
|
import { useAppDispatch } from "./state/hooks";
|
||||||
import { updateSettings, useSettings } from "./state/settingsSlice";
|
import { updateSettings, useSettings } from "./state/settingsSlice";
|
||||||
import SettingsMenu from "./components/SettingsMenu";
|
import SettingsMenu from "./components/SettingsMenu";
|
||||||
|
import ReadinessWrapper from "./components/ReadinessWrapper";
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
|
@ -379,15 +380,42 @@ function App() {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{agentMode ? (
|
{agentMode ? (
|
||||||
<Route path="/agent" element={<AgentPage />} />
|
<Route
|
||||||
|
path="/agent"
|
||||||
|
element={
|
||||||
|
<ReadinessWrapper>
|
||||||
|
<AgentPage />
|
||||||
|
</ReadinessWrapper>
|
||||||
|
}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Route path="/query" element={<QueryPage />} />
|
<Route
|
||||||
<Route path="/alerts" element={<AlertsPage />} />
|
path="/query"
|
||||||
|
element={
|
||||||
|
<ReadinessWrapper>
|
||||||
|
<QueryPage />
|
||||||
|
</ReadinessWrapper>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/alerts"
|
||||||
|
element={
|
||||||
|
<ReadinessWrapper>
|
||||||
|
<AlertsPage />
|
||||||
|
</ReadinessWrapper>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{allStatusPages.map((p) => (
|
{allStatusPages.map((p) => (
|
||||||
<Route key={p.path} path={p.path} element={p.element} />
|
<Route
|
||||||
|
key={p.path}
|
||||||
|
path={p.path}
|
||||||
|
element={
|
||||||
|
<ReadinessWrapper>{p.element}</ReadinessWrapper>
|
||||||
|
}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Routes>
|
</Routes>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
7
web/ui/mantine-ui/src/api/responseTypes/walreplay.ts
Normal file
7
web/ui/mantine-ui/src/api/responseTypes/walreplay.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// Result type for /api/v1/status/walreplay endpoint.
|
||||||
|
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#wal-replay-stats
|
||||||
|
export interface WALReplayStatus {
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
current: number;
|
||||||
|
}
|
92
web/ui/mantine-ui/src/components/ReadinessWrapper.tsx
Normal file
92
web/ui/mantine-ui/src/components/ReadinessWrapper.tsx
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
import { FC, PropsWithChildren, useEffect, useState } from "react";
|
||||||
|
import { useAppDispatch } from "../state/hooks";
|
||||||
|
import { updateSettings, useSettings } from "../state/settingsSlice";
|
||||||
|
import { useSuspenseAPIQuery } from "../api/api";
|
||||||
|
import { WALReplayStatus } from "../api/responseTypes/walreplay";
|
||||||
|
import { Progress, Stack, Title } from "@mantine/core";
|
||||||
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
const ReadinessLoader: FC = () => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
// Query key is incremented every second to retrigger the status fetching.
|
||||||
|
const [queryKey, setQueryKey] = useState(0);
|
||||||
|
|
||||||
|
// Query readiness status.
|
||||||
|
const { data: ready } = useSuspenseQuery<boolean>({
|
||||||
|
queryKey: [`ready-${queryKey}`],
|
||||||
|
retry: false,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
gcTime: 0,
|
||||||
|
queryFn: async ({ signal }: { signal: AbortSignal }) => {
|
||||||
|
try {
|
||||||
|
const res = await fetch("/-/ready", {
|
||||||
|
cache: "no-store",
|
||||||
|
credentials: "same-origin",
|
||||||
|
signal,
|
||||||
|
});
|
||||||
|
switch (res.status) {
|
||||||
|
case 200:
|
||||||
|
return true;
|
||||||
|
case 503:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
throw new Error(res.statusText);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error("Unexpected error while fetching ready status");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Query WAL replay status.
|
||||||
|
const {
|
||||||
|
data: {
|
||||||
|
data: { min, max, current },
|
||||||
|
},
|
||||||
|
} = useSuspenseAPIQuery<WALReplayStatus>({
|
||||||
|
path: `/status/walreplay`,
|
||||||
|
key: `walreplay-${queryKey}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ready) {
|
||||||
|
dispatch(updateSettings({ ready: ready }));
|
||||||
|
}
|
||||||
|
}, [ready, dispatch]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => setQueryKey((v) => v + 1), 1000);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap="lg" maw={1000} mx="auto" mt="xs">
|
||||||
|
<Title order={2}>Starting up...</Title>
|
||||||
|
{max > 0 && (
|
||||||
|
<>
|
||||||
|
<p>
|
||||||
|
Replaying WAL ({current}/{max})
|
||||||
|
</p>
|
||||||
|
<Progress
|
||||||
|
size="xl"
|
||||||
|
animated
|
||||||
|
value={((current - min + 1) / (max - min + 1)) * 100}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ReadinessWrapper: FC<PropsWithChildren> = ({ children }) => {
|
||||||
|
const { ready } = useSettings();
|
||||||
|
|
||||||
|
if (ready) {
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ReadinessLoader />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ReadinessWrapper;
|
|
@ -9,6 +9,9 @@ export default defineConfig({
|
||||||
"/api": {
|
"/api": {
|
||||||
target: "http://localhost:9090",
|
target: "http://localhost:9090",
|
||||||
},
|
},
|
||||||
|
"/-/": {
|
||||||
|
target: "http://localhost:9090",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue