Skip to content

Commit 5716ef4

Browse files
committed
feat : health check rustfs/rustfs#2096
1 parent eebeb45 commit 5716ef4

2 files changed

Lines changed: 71 additions & 4 deletions

File tree

‎app/(auth)/config/page.tsx‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { useMessage } from "@/lib/feedback/message"
1515
import { buildRoute, getLoginRoute } from "@/lib/routes"
1616
import logoImage from "@/assets/logo.svg"
1717
import { configManager } from "@/lib/config"
18+
import { checkServerHealth } from "@/lib/config-helpers"
1819

1920
export default function ConfigPage() {
2021
return (
@@ -32,9 +33,12 @@ function ConfigPageContent() {
3233
const [serverHost, setServerHost] = useState(() =>
3334
typeof window !== "undefined" ? (localStorage.getItem("rustfs-server-host") ?? "") : "",
3435
)
36+
const [isSaving, setIsSaving] = useState(false)
3537

3638
const validateAndSave = async (e: React.FormEvent) => {
3739
e.preventDefault()
40+
setIsSaving(true)
41+
3842
try {
3943
if (serverHost) {
4044
let urlToValidate = serverHost.trim()
@@ -45,7 +49,16 @@ function ConfigPageContent() {
4549

4650
new URL(urlToValidate)
4751

48-
const urlToSave = serverHost.match(/^https?:\/\//) ? serverHost : urlToValidate
52+
const urlToSave = urlToValidate
53+
54+
const healthResult = await checkServerHealth(urlToSave)
55+
if (!healthResult.healthy) {
56+
message.error(
57+
`${t("Unable to reach RustFS server health endpoint")}: ${healthResult.error ?? t("Request failed")}`,
58+
)
59+
return
60+
}
61+
4962
localStorage.setItem("rustfs-server-host", urlToSave)
5063

5164
if (!serverHost.match(/^https?:\/\//)) {
@@ -64,6 +77,8 @@ function ConfigPageContent() {
6477
}, 200)
6578
} catch (error) {
6679
message.error(t("Invalid server address format") + ": " + (error as Error).message)
80+
} finally {
81+
setIsSaving(false)
6782
}
6883
}
6984

@@ -125,15 +140,15 @@ function ConfigPageContent() {
125140
</Field>
126141

127142
<div className="flex gap-3">
128-
<Button type="submit" className="flex-1">
143+
<Button type="submit" className="flex-1" disabled={isSaving}>
129144
{t("Save Configuration")}
130145
</Button>
131146

132-
<Button type="button" variant="outline" onClick={resetToCurrentHost}>
147+
<Button type="button" variant="outline" onClick={resetToCurrentHost} disabled={isSaving}>
133148
{t("Reset")}
134149
</Button>
135150

136-
<Button type="button" variant="outline" onClick={skipConfig}>
151+
<Button type="button" variant="outline" onClick={skipConfig} disabled={isSaving}>
137152
{t("Skip")}
138153
</Button>
139154
</div>

‎lib/config-helpers.ts‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,22 @@ interface HostInfo {
2222
serverHost: string
2323
}
2424

25+
export interface ServerHealthCheckResult {
26+
healthy: boolean
27+
url?: string
28+
status?: number
29+
error?: string
30+
}
31+
2532
const STORAGE_KEY = "rustfs-server-host"
2633
const CREDENTIALS_KEY = "auth.credentials"
2734
const PERMANENT_CREDENTIALS_KEY = "auth.permanent"
2835
const DEFAULT_REGION = "us-east-1"
2936
const API_PATH = "/rustfs/admin/v3"
3037
const VERSION_PATH = "/rustfs/console/version"
3138
const REQUEST_TIMEOUT = 5000
39+
const HEALTH_REQUEST_TIMEOUT = 5000
40+
const HEALTH_PATHS = ["/rustfs/console/health", "/health"] as const
3241

3342
const isBrowser = (): boolean => typeof window !== "undefined"
3443

@@ -185,6 +194,49 @@ export const fetchVersionConfigFromServer = async (serverHost: string): Promise<
185194
}
186195
}
187196

197+
const requestHealth = async (url: string): Promise<Response> => {
198+
const headResponse = await fetch(url, {
199+
method: "HEAD",
200+
signal: AbortSignal.timeout(HEALTH_REQUEST_TIMEOUT),
201+
})
202+
203+
if (headResponse.status !== 405) return headResponse
204+
205+
return fetch(url, {
206+
method: "GET",
207+
signal: AbortSignal.timeout(HEALTH_REQUEST_TIMEOUT),
208+
})
209+
}
210+
211+
export const checkServerHealth = async (serverHost: string): Promise<ServerHealthCheckResult> => {
212+
const normalizedHost = serverHost.replace(/\/+$/, "")
213+
let lastError = "Unknown health check error"
214+
215+
for (const path of HEALTH_PATHS) {
216+
const healthUrl = `${normalizedHost}${path}`
217+
218+
try {
219+
const response = await requestHealth(healthUrl)
220+
if (response.ok) {
221+
return {
222+
healthy: true,
223+
url: healthUrl,
224+
status: response.status,
225+
}
226+
}
227+
228+
lastError = `${response.status} ${response.statusText || "Health check failed"}`
229+
} catch (error) {
230+
lastError = error instanceof Error ? error.message : "Health check request failed"
231+
}
232+
}
233+
234+
return {
235+
healthy: false,
236+
error: lastError,
237+
}
238+
}
239+
188240
export const getServerDefaultConfig = (): ConfigResult => {
189241
const defaultServerHost = "http://localhost:9000"
190242
const config = createDefaultConfig(defaultServerHost)

0 commit comments

Comments
 (0)