fix(data-collection): улучшить обработку ошибок и загрузку данных с API
Docker images / prepare-release (push) Successful in 5s
Docker images / backend-image (push) Successful in 1m32s
Docker images / frontend-image (push) Successful in 1m41s
Docker images / updater-image (push) Successful in 37s
Docker images / notify-webhook (push) Has been skipped
Docker images / publish-release (push) Successful in 7s
Docker images / prepare-release (push) Successful in 5s
Docker images / backend-image (push) Successful in 1m32s
Docker images / frontend-image (push) Successful in 1m41s
Docker images / updater-image (push) Successful in 37s
Docker images / notify-webhook (push) Has been skipped
Docker images / publish-release (push) Successful in 7s
This commit is contained in:
@@ -24,7 +24,7 @@ import {
|
||||
type SchedulerRunRowDto,
|
||||
type UptimeSettingsDto,
|
||||
} from "@/lib/scheduler-settings"
|
||||
import { requestJson } from "@/shared/api/http-client"
|
||||
import { requestJson, ApiClientError } from "@/shared/api/http-client"
|
||||
import {
|
||||
parseSchedulerRunSnapshot,
|
||||
type AlertEngineRuleDiagSnapshot,
|
||||
@@ -58,6 +58,27 @@ function makeApiFetch(backendUrl: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function extractApiError(reason: unknown): string {
|
||||
if (reason instanceof ApiClientError) return reason.message
|
||||
if (reason instanceof Error) return reason.message
|
||||
return String(reason)
|
||||
}
|
||||
|
||||
function readSettled<T>(result: PromiseSettledResult<T>): T | null {
|
||||
return result.status === "fulfilled" ? result.value : null
|
||||
}
|
||||
|
||||
function collectSettledErrors(results: PromiseSettledResult<unknown>[], labels: string[]): string[] {
|
||||
const errors: string[] = []
|
||||
for (let i = 0; i < results.length; i += 1) {
|
||||
const result = results[i]
|
||||
if (result.status === "rejected") {
|
||||
errors.push(`${labels[i]}: ${extractApiError(result.reason)}`)
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
function Toggle({ checked, onChange }: { checked: boolean; onChange: (v: boolean) => void }) {
|
||||
return (
|
||||
<button
|
||||
@@ -786,7 +807,7 @@ export default function DataCollectionPage() {
|
||||
runFilterJobKey && SCHEDULER_JOB_KEYS.includes(runFilterJobKey as (typeof SCHEDULER_JOB_KEYS)[number])
|
||||
? `?limit=80&jobKey=${encodeURIComponent(runFilterJobKey)}`
|
||||
: "?limit=80"
|
||||
const [traffic, serversApi, uptime, internetPath, certRenew, runsRes] = await Promise.all([
|
||||
const [trafficRes, serversApiRes, uptimeRes, internetPathRes, certRenewRes, runsRes] = await Promise.allSettled([
|
||||
apiFetch<CollectorSettingsDto>("/api/traffic/settings"),
|
||||
apiFetch<CollectorSettingsDto>("/api/servers-api-ping/settings"),
|
||||
apiFetch<UptimeSettingsDto>("/api/uptime/settings"),
|
||||
@@ -794,28 +815,60 @@ export default function DataCollectionPage() {
|
||||
apiFetch<{ enabled: boolean; intervalSec: number; renewBeforeDays: number }>("/api/certificates/renew-settings"),
|
||||
apiFetch<{ runs: SchedulerRunRowDto[] }>(`/api/scheduler/runs${runsQuery}`),
|
||||
])
|
||||
setTrafficCollector(traffic)
|
||||
setServersApiCollector(serversApi)
|
||||
setUptimeCollector(uptime)
|
||||
setInternetPathCollector(internetPath)
|
||||
setSchedulerRuns(runsRes.runs ?? [])
|
||||
setTrafficIntervalDraft(String(traffic.intervalSec))
|
||||
setTrafficRetentionDraft(String(traffic.retentionDays))
|
||||
setUptimeResourceIntervalDraft(String(uptime.intervalSec ?? 300))
|
||||
setUptimeIntervalDraft(String(uptime.probeIntervalSec ?? 15))
|
||||
setUptimeSpeedIntervalDraft(String(uptime.speedIntervalSec ?? 60))
|
||||
setUptimeRetentionDraft(String(uptime.retentionDays))
|
||||
setDraftTrafficEnabled(!!traffic.enabled)
|
||||
setDraftServersApiEnabled(!!serversApi.enabled)
|
||||
setServersApiIntervalDraft(String(serversApi.intervalSec ?? 120))
|
||||
setDraftResourcesEnabled(!!(uptime.resourcesEnabled ?? uptime.enabled))
|
||||
setDraftPingEnabled(!!(uptime.pingEnabled ?? uptime.enabled))
|
||||
setDraftSpeedEnabled(!!(uptime.speedEnabled ?? uptime.enabled))
|
||||
setDraftInternetPathEnabled(!!internetPath.enabled)
|
||||
setInternetPathIntervalDraft(String(internetPath.intervalSec ?? 300))
|
||||
setDraftCertRenewEnabled(!!certRenew.enabled)
|
||||
setCertRenewIntervalDraft(String(certRenew.intervalSec ?? 21600))
|
||||
setRenewBeforeDaysDraft(String(certRenew.renewBeforeDays ?? 30))
|
||||
|
||||
const loadErrors = collectSettledErrors(
|
||||
[trafficRes, serversApiRes, uptimeRes, internetPathRes, certRenewRes, runsRes],
|
||||
["трафик", "серверы REST API", "uptime", "internet path", "сертификаты", "журнал планировщика"],
|
||||
)
|
||||
if (loadErrors.length > 0) {
|
||||
setCollectorError(loadErrors.join("; "))
|
||||
}
|
||||
|
||||
const traffic = readSettled(trafficRes)
|
||||
if (traffic) {
|
||||
setTrafficCollector(traffic)
|
||||
setTrafficIntervalDraft(String(traffic.intervalSec))
|
||||
setTrafficRetentionDraft(String(traffic.retentionDays))
|
||||
setDraftTrafficEnabled(!!traffic.enabled)
|
||||
}
|
||||
|
||||
const serversApi = readSettled(serversApiRes)
|
||||
if (serversApi) {
|
||||
setServersApiCollector(serversApi)
|
||||
setDraftServersApiEnabled(!!serversApi.enabled)
|
||||
setServersApiIntervalDraft(String(serversApi.intervalSec ?? 120))
|
||||
}
|
||||
|
||||
const uptime = readSettled(uptimeRes)
|
||||
if (uptime) {
|
||||
setUptimeCollector(uptime)
|
||||
setUptimeResourceIntervalDraft(String(uptime.intervalSec ?? 300))
|
||||
setUptimeIntervalDraft(String(uptime.probeIntervalSec ?? 15))
|
||||
setUptimeSpeedIntervalDraft(String(uptime.speedIntervalSec ?? 60))
|
||||
setUptimeRetentionDraft(String(uptime.retentionDays))
|
||||
setDraftResourcesEnabled(!!(uptime.resourcesEnabled ?? uptime.enabled))
|
||||
setDraftPingEnabled(!!(uptime.pingEnabled ?? uptime.enabled))
|
||||
setDraftSpeedEnabled(!!(uptime.speedEnabled ?? uptime.enabled))
|
||||
}
|
||||
|
||||
const internetPath = readSettled(internetPathRes)
|
||||
if (internetPath) {
|
||||
setInternetPathCollector(internetPath)
|
||||
setDraftInternetPathEnabled(!!internetPath.enabled)
|
||||
setInternetPathIntervalDraft(String(internetPath.intervalSec ?? 300))
|
||||
}
|
||||
|
||||
const certRenew = readSettled(certRenewRes)
|
||||
if (certRenew) {
|
||||
setDraftCertRenewEnabled(!!certRenew.enabled)
|
||||
setCertRenewIntervalDraft(String(certRenew.intervalSec ?? 21600))
|
||||
setRenewBeforeDaysDraft(String(certRenew.renewBeforeDays ?? 30))
|
||||
}
|
||||
|
||||
const runsPayload = readSettled(runsRes)
|
||||
if (runsPayload) {
|
||||
setSchedulerRuns(runsPayload.runs ?? [])
|
||||
}
|
||||
} catch (e) {
|
||||
setCollectorError(e instanceof Error ? e.message : "Не удалось загрузить данные")
|
||||
} finally {
|
||||
@@ -1226,51 +1279,60 @@ export default function DataCollectionPage() {
|
||||
const uRet = Math.max(1, Number.parseInt(uptimeRetentionDraft, 10) || 14)
|
||||
const sApiInt = Math.max(10, Number.parseInt(serversApiIntervalDraft, 10) || 120)
|
||||
const ipInt = Math.max(30, Number.parseInt(internetPathIntervalDraft, 10) || 300)
|
||||
await apiFetch("/api/traffic/settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
enabled: draftTrafficEnabled,
|
||||
intervalSec: tInt,
|
||||
retentionDays: tRet,
|
||||
}),
|
||||
})
|
||||
await apiFetch("/api/servers-api-ping/settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
enabled: draftServersApiEnabled,
|
||||
intervalSec: sApiInt,
|
||||
}),
|
||||
})
|
||||
await apiFetch("/api/uptime/settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
resourcesEnabled: draftResourcesEnabled,
|
||||
pingEnabled: draftPingEnabled,
|
||||
speedEnabled: draftSpeedEnabled,
|
||||
intervalSec: uRes,
|
||||
probeIntervalSec: uPing,
|
||||
speedIntervalSec: uSpd,
|
||||
retentionDays: uRet,
|
||||
}),
|
||||
})
|
||||
const certRenewInt = Math.max(300, Number.parseInt(certRenewIntervalDraft, 10) || 21600)
|
||||
const renewBeforeDays = Math.max(1, Math.min(90, Number.parseInt(renewBeforeDaysDraft, 10) || 30))
|
||||
await apiFetch("/api/internet-path/settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
enabled: draftInternetPathEnabled,
|
||||
intervalSec: ipInt,
|
||||
const saveResults = await Promise.allSettled([
|
||||
apiFetch("/api/traffic/settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
enabled: draftTrafficEnabled,
|
||||
intervalSec: tInt,
|
||||
retentionDays: tRet,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
await apiFetch("/api/certificates/renew-settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
enabled: draftCertRenewEnabled,
|
||||
intervalSec: certRenewInt,
|
||||
renewBeforeDays,
|
||||
apiFetch("/api/servers-api-ping/settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
enabled: draftServersApiEnabled,
|
||||
intervalSec: sApiInt,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
apiFetch("/api/uptime/settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
resourcesEnabled: draftResourcesEnabled,
|
||||
pingEnabled: draftPingEnabled,
|
||||
speedEnabled: draftSpeedEnabled,
|
||||
intervalSec: uRes,
|
||||
probeIntervalSec: uPing,
|
||||
speedIntervalSec: uSpd,
|
||||
retentionDays: uRet,
|
||||
}),
|
||||
}),
|
||||
apiFetch("/api/internet-path/settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
enabled: draftInternetPathEnabled,
|
||||
intervalSec: ipInt,
|
||||
}),
|
||||
}),
|
||||
apiFetch("/api/certificates/renew-settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
enabled: draftCertRenewEnabled,
|
||||
intervalSec: certRenewInt,
|
||||
renewBeforeDays,
|
||||
}),
|
||||
}),
|
||||
])
|
||||
const saveErrors = collectSettledErrors(
|
||||
saveResults,
|
||||
["трафик", "серверы REST API", "uptime", "internet path", "сертификаты"],
|
||||
)
|
||||
await loadCollectors()
|
||||
if (saveErrors.length > 0) {
|
||||
setCollectorError(`Не все настройки сохранились: ${saveErrors.join("; ")}`)
|
||||
}
|
||||
} catch (e) {
|
||||
setCollectorError(e instanceof Error ? e.message : "Не удалось сохранить")
|
||||
} finally {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user