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 SchedulerRunRowDto,
|
||||||
type UptimeSettingsDto,
|
type UptimeSettingsDto,
|
||||||
} from "@/lib/scheduler-settings"
|
} from "@/lib/scheduler-settings"
|
||||||
import { requestJson } from "@/shared/api/http-client"
|
import { requestJson, ApiClientError } from "@/shared/api/http-client"
|
||||||
import {
|
import {
|
||||||
parseSchedulerRunSnapshot,
|
parseSchedulerRunSnapshot,
|
||||||
type AlertEngineRuleDiagSnapshot,
|
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 }) {
|
function Toggle({ checked, onChange }: { checked: boolean; onChange: (v: boolean) => void }) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
@@ -786,7 +807,7 @@ export default function DataCollectionPage() {
|
|||||||
runFilterJobKey && SCHEDULER_JOB_KEYS.includes(runFilterJobKey as (typeof SCHEDULER_JOB_KEYS)[number])
|
runFilterJobKey && SCHEDULER_JOB_KEYS.includes(runFilterJobKey as (typeof SCHEDULER_JOB_KEYS)[number])
|
||||||
? `?limit=80&jobKey=${encodeURIComponent(runFilterJobKey)}`
|
? `?limit=80&jobKey=${encodeURIComponent(runFilterJobKey)}`
|
||||||
: "?limit=80"
|
: "?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/traffic/settings"),
|
||||||
apiFetch<CollectorSettingsDto>("/api/servers-api-ping/settings"),
|
apiFetch<CollectorSettingsDto>("/api/servers-api-ping/settings"),
|
||||||
apiFetch<UptimeSettingsDto>("/api/uptime/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<{ enabled: boolean; intervalSec: number; renewBeforeDays: number }>("/api/certificates/renew-settings"),
|
||||||
apiFetch<{ runs: SchedulerRunRowDto[] }>(`/api/scheduler/runs${runsQuery}`),
|
apiFetch<{ runs: SchedulerRunRowDto[] }>(`/api/scheduler/runs${runsQuery}`),
|
||||||
])
|
])
|
||||||
setTrafficCollector(traffic)
|
|
||||||
setServersApiCollector(serversApi)
|
const loadErrors = collectSettledErrors(
|
||||||
setUptimeCollector(uptime)
|
[trafficRes, serversApiRes, uptimeRes, internetPathRes, certRenewRes, runsRes],
|
||||||
setInternetPathCollector(internetPath)
|
["трафик", "серверы REST API", "uptime", "internet path", "сертификаты", "журнал планировщика"],
|
||||||
setSchedulerRuns(runsRes.runs ?? [])
|
)
|
||||||
setTrafficIntervalDraft(String(traffic.intervalSec))
|
if (loadErrors.length > 0) {
|
||||||
setTrafficRetentionDraft(String(traffic.retentionDays))
|
setCollectorError(loadErrors.join("; "))
|
||||||
setUptimeResourceIntervalDraft(String(uptime.intervalSec ?? 300))
|
}
|
||||||
setUptimeIntervalDraft(String(uptime.probeIntervalSec ?? 15))
|
|
||||||
setUptimeSpeedIntervalDraft(String(uptime.speedIntervalSec ?? 60))
|
const traffic = readSettled(trafficRes)
|
||||||
setUptimeRetentionDraft(String(uptime.retentionDays))
|
if (traffic) {
|
||||||
setDraftTrafficEnabled(!!traffic.enabled)
|
setTrafficCollector(traffic)
|
||||||
setDraftServersApiEnabled(!!serversApi.enabled)
|
setTrafficIntervalDraft(String(traffic.intervalSec))
|
||||||
setServersApiIntervalDraft(String(serversApi.intervalSec ?? 120))
|
setTrafficRetentionDraft(String(traffic.retentionDays))
|
||||||
setDraftResourcesEnabled(!!(uptime.resourcesEnabled ?? uptime.enabled))
|
setDraftTrafficEnabled(!!traffic.enabled)
|
||||||
setDraftPingEnabled(!!(uptime.pingEnabled ?? uptime.enabled))
|
}
|
||||||
setDraftSpeedEnabled(!!(uptime.speedEnabled ?? uptime.enabled))
|
|
||||||
setDraftInternetPathEnabled(!!internetPath.enabled)
|
const serversApi = readSettled(serversApiRes)
|
||||||
setInternetPathIntervalDraft(String(internetPath.intervalSec ?? 300))
|
if (serversApi) {
|
||||||
setDraftCertRenewEnabled(!!certRenew.enabled)
|
setServersApiCollector(serversApi)
|
||||||
setCertRenewIntervalDraft(String(certRenew.intervalSec ?? 21600))
|
setDraftServersApiEnabled(!!serversApi.enabled)
|
||||||
setRenewBeforeDaysDraft(String(certRenew.renewBeforeDays ?? 30))
|
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) {
|
} catch (e) {
|
||||||
setCollectorError(e instanceof Error ? e.message : "Не удалось загрузить данные")
|
setCollectorError(e instanceof Error ? e.message : "Не удалось загрузить данные")
|
||||||
} finally {
|
} finally {
|
||||||
@@ -1226,51 +1279,60 @@ export default function DataCollectionPage() {
|
|||||||
const uRet = Math.max(1, Number.parseInt(uptimeRetentionDraft, 10) || 14)
|
const uRet = Math.max(1, Number.parseInt(uptimeRetentionDraft, 10) || 14)
|
||||||
const sApiInt = Math.max(10, Number.parseInt(serversApiIntervalDraft, 10) || 120)
|
const sApiInt = Math.max(10, Number.parseInt(serversApiIntervalDraft, 10) || 120)
|
||||||
const ipInt = Math.max(30, Number.parseInt(internetPathIntervalDraft, 10) || 300)
|
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 certRenewInt = Math.max(300, Number.parseInt(certRenewIntervalDraft, 10) || 21600)
|
||||||
const renewBeforeDays = Math.max(1, Math.min(90, Number.parseInt(renewBeforeDaysDraft, 10) || 30))
|
const renewBeforeDays = Math.max(1, Math.min(90, Number.parseInt(renewBeforeDaysDraft, 10) || 30))
|
||||||
await apiFetch("/api/internet-path/settings", {
|
const saveResults = await Promise.allSettled([
|
||||||
method: "PUT",
|
apiFetch("/api/traffic/settings", {
|
||||||
body: JSON.stringify({
|
method: "PUT",
|
||||||
enabled: draftInternetPathEnabled,
|
body: JSON.stringify({
|
||||||
intervalSec: ipInt,
|
enabled: draftTrafficEnabled,
|
||||||
|
intervalSec: tInt,
|
||||||
|
retentionDays: tRet,
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
apiFetch("/api/servers-api-ping/settings", {
|
||||||
await apiFetch("/api/certificates/renew-settings", {
|
method: "PUT",
|
||||||
method: "PUT",
|
body: JSON.stringify({
|
||||||
body: JSON.stringify({
|
enabled: draftServersApiEnabled,
|
||||||
enabled: draftCertRenewEnabled,
|
intervalSec: sApiInt,
|
||||||
intervalSec: certRenewInt,
|
}),
|
||||||
renewBeforeDays,
|
|
||||||
}),
|
}),
|
||||||
})
|
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()
|
await loadCollectors()
|
||||||
|
if (saveErrors.length > 0) {
|
||||||
|
setCollectorError(`Не все настройки сохранились: ${saveErrors.join("; ")}`)
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setCollectorError(e instanceof Error ? e.message : "Не удалось сохранить")
|
setCollectorError(e instanceof Error ? e.message : "Не удалось сохранить")
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user