fix(scheduler): показывать подтверждённый статус независимо от настроек uptime
This commit is contained in:
1 parent
1f75bc5cea
commit
5d5ea680aa
5 files changed
+87
-51
No files matched your search
@@ -22,10 +22,11 @@ import {
|
||||
SCHEDULER_JOB_LABELS,
|
||||
type CollectorSettingsDto,
|
||||
type SchedulerJobStatusDto,
|
||||
type SchedulerStatusDto,
|
||||
type SchedulerRunRowDto,
|
||||
type UptimeSettingsDto,
|
||||
} from "@/lib/scheduler-settings"
|
||||
import { listSchedulerRuns } from "@/shared/api/scheduler"
|
||||
import { getSchedulerStatus, listSchedulerRuns } from "@/shared/api/scheduler"
|
||||
import { requestJson, ApiClientError } from "@/shared/api/http-client"
|
||||
import {
|
||||
parseSchedulerRunSnapshot,
|
||||
@@ -586,6 +587,9 @@ function DataCollectionContent() {
|
||||
const [certRenewIntervalDraft, setCertRenewIntervalDraft] = useState("21600")
|
||||
const [renewBeforeDaysDraft, setRenewBeforeDaysDraft] = useState("30")
|
||||
const [schedulerRuns, setSchedulerRuns] = useState<SchedulerRunRowDto[]>([])
|
||||
const [schedulerStatus, setSchedulerStatus] = useState<SchedulerStatusDto | null>(null)
|
||||
const [schedulerStatusError, setSchedulerStatusError] = useState<string | null>(null)
|
||||
const [schedulerStatusReceivedAt, setSchedulerStatusReceivedAt] = useState<string | null>(null)
|
||||
const [runsKnown, setRunsKnown] = useState(false)
|
||||
const [runsError, setRunsError] = useState<string | null>(null)
|
||||
const [runsReceivedAt, setRunsReceivedAt] = useState<string | null>(null)
|
||||
@@ -613,9 +617,9 @@ function DataCollectionContent() {
|
||||
}, [])
|
||||
|
||||
const schedulerJobsByKey = useMemo(() => {
|
||||
const jobs = uptimeCollector?.scheduler?.jobs ?? []
|
||||
const jobs = schedulerStatus?.jobs ?? []
|
||||
return Object.fromEntries(jobs.map((j) => [j.jobKey, j])) as Record<string, SchedulerJobStatusDto>
|
||||
}, [uptimeCollector?.scheduler?.jobs])
|
||||
}, [schedulerStatus?.jobs])
|
||||
|
||||
const loadCollectors = useCallback(async () => {
|
||||
if (!isLive || !reader.current.active) return
|
||||
@@ -628,19 +632,27 @@ function DataCollectionContent() {
|
||||
setPageBusy(true)
|
||||
try {
|
||||
const runsFilter = runFilterJobKey && SCHEDULER_JOB_KEYS.includes(runFilterJobKey as (typeof SCHEDULER_JOB_KEYS)[number]) ? runFilterJobKey as (typeof SCHEDULER_JOB_KEYS)[number] : undefined
|
||||
const [trafficRes, serversApiRes, uptimeRes, internetPathRes, certRenewRes, runsRes] = await Promise.allSettled([
|
||||
const runsRequest = listSchedulerRuns(backendUrl, { limit: 80, jobKey: runsFilter }, { signal }).then(data => {
|
||||
if (current()) { setSchedulerRuns(data.runs); setRunsKnown(true); setRunsError(null); setRunsReceivedAt(new Date().toISOString()) }
|
||||
return data
|
||||
}, error => { if (current()) setRunsError(extractApiError(error)); throw error })
|
||||
const statusRequest = getSchedulerStatus(backendUrl, { signal }).then(data => {
|
||||
if (current()) { setSchedulerStatus(data); setSchedulerStatusError(null); setSchedulerStatusReceivedAt(new Date().toISOString()) }
|
||||
return data
|
||||
}, error => { if (current()) setSchedulerStatusError(extractApiError(error)); throw error })
|
||||
const [trafficRes, serversApiRes, uptimeRes, internetPathRes, certRenewRes, runsRes, statusRes] = await Promise.allSettled([
|
||||
apiFetch<CollectorSettingsDto>("/api/traffic/settings", { signal }),
|
||||
apiFetch<CollectorSettingsDto>("/api/servers-api-ping/settings", { signal }),
|
||||
apiFetch<UptimeSettingsDto>("/api/uptime/settings", { signal }),
|
||||
apiFetch<CollectorSettingsDto>("/api/internet-path/settings", { signal }),
|
||||
apiFetch<{ enabled: boolean; intervalSec: number; renewBeforeDays: number }>("/api/certificates/renew-settings", { signal }),
|
||||
listSchedulerRuns(backendUrl, { limit: 80, jobKey: runsFilter }, { signal }),
|
||||
runsRequest, statusRequest,
|
||||
])
|
||||
|
||||
if (!current()) return
|
||||
const loadErrors = collectSettledErrors(
|
||||
[trafficRes, serversApiRes, uptimeRes, internetPathRes, certRenewRes, runsRes],
|
||||
["трафик", "серверы REST API", "uptime", "internet path", "сертификаты", "журнал планировщика"],
|
||||
[trafficRes, serversApiRes, uptimeRes, internetPathRes, certRenewRes, runsRes, statusRes],
|
||||
["трафик", "серверы REST API", "uptime", "internet path", "сертификаты", "журнал планировщика", "статус планировщика"],
|
||||
)
|
||||
if (loadErrors.length > 0) {
|
||||
setCollectorError(loadErrors.join("; "))
|
||||
@@ -698,13 +710,6 @@ function DataCollectionContent() {
|
||||
setRenewBeforeDaysDraft(String(certRenew.renewBeforeDays ?? 30))
|
||||
}
|
||||
|
||||
const runsPayload = readSettled(runsRes)
|
||||
if (runsPayload) {
|
||||
setSchedulerRuns(runsPayload.runs)
|
||||
setRunsKnown(true); setRunsError(null); setRunsReceivedAt(new Date().toISOString())
|
||||
} else if (runsRes.status === "rejected") {
|
||||
setRunsError(extractApiError(runsRes.reason))
|
||||
}
|
||||
} catch (e) {
|
||||
if (current()) setCollectorError(e instanceof Error ? e.message : "Не удалось загрузить данные")
|
||||
} finally {
|
||||
@@ -984,51 +989,23 @@ function DataCollectionContent() {
|
||||
uptimeSpeedIntervalDraft,
|
||||
])
|
||||
|
||||
const enabledJobsCount = useMemo(() => {
|
||||
const jobs = uptimeCollector?.scheduler?.jobs
|
||||
if (jobs?.length) return jobs.filter((job) => job.enabled).length
|
||||
|
||||
let n = draftTrafficEnabled ? 1 : 0
|
||||
if (draftServersApiEnabled) n += 1
|
||||
if (draftResourcesEnabled) n += 1
|
||||
if (draftPingEnabled) n += 1
|
||||
if (draftSpeedEnabled) n += 1
|
||||
if (draftInternetPathEnabled) n += 1
|
||||
if (draftCertRenewEnabled) n += 1
|
||||
return n
|
||||
}, [
|
||||
draftCertRenewEnabled,
|
||||
draftInternetPathEnabled,
|
||||
draftPingEnabled,
|
||||
draftResourcesEnabled,
|
||||
draftServersApiEnabled,
|
||||
draftSpeedEnabled,
|
||||
draftTrafficEnabled,
|
||||
uptimeCollector?.scheduler?.jobs,
|
||||
])
|
||||
|
||||
const schedulerJobCount = SCHEDULER_JOB_KEYS.length
|
||||
|
||||
const runningJobsCount = useMemo(
|
||||
() => (uptimeCollector?.scheduler?.jobs ?? []).filter((j) => j.running).length,
|
||||
[uptimeCollector?.scheduler?.jobs],
|
||||
)
|
||||
const enabledJobsCount = schedulerStatus?.jobs.filter(job => job.enabled).length ?? 0
|
||||
const schedulerJobCount = schedulerStatus?.jobs.length ?? 0
|
||||
const runningJobsCount = schedulerStatus?.jobs.filter(job => job.running).length ?? 0
|
||||
|
||||
const errorRunsInView = useMemo(() => schedulerRuns.filter((r) => r.status === "error").length, [schedulerRuns])
|
||||
|
||||
const stats = [
|
||||
{
|
||||
label: "Включено задач",
|
||||
value: `${enabledJobsCount} / ${schedulerJobCount}`,
|
||||
sub: uptimeCollector?.scheduler?.jobs?.length
|
||||
? "По сохранённым задачам планировщика"
|
||||
: "По переключателям на этой странице",
|
||||
value: schedulerStatus ? `${enabledJobsCount} / ${schedulerJobCount}` : "—",
|
||||
sub: schedulerStatusError ? (schedulerStatus ? "Последний подтверждённый статус" : "Статус не получен") : schedulerStatus ? "По сохранённым задачам планировщика" : "Ожидание статуса",
|
||||
icon: <CalendarClockIcon className="size-4" />,
|
||||
},
|
||||
{
|
||||
label: "Сейчас выполняется",
|
||||
value: String(runningJobsCount),
|
||||
sub: "Фоновые прогоны планировщика",
|
||||
value: schedulerStatus ? String(runningJobsCount) : "—",
|
||||
sub: schedulerStatusError ? "Статус требует обновления" : "Фоновые прогоны планировщика",
|
||||
icon: <LoaderCircleIcon className="size-4" />,
|
||||
},
|
||||
{
|
||||
@@ -1099,6 +1076,14 @@ function DataCollectionContent() {
|
||||
</OpsPanel>
|
||||
)}
|
||||
|
||||
{isLive && schedulerStatusError ? (
|
||||
<Alert variant="warning">
|
||||
<AlertCircleIcon aria-hidden="true" />
|
||||
<AlertTitle>{schedulerStatus ? "Статус планировщика не обновлён" : "Статус планировщика не получен"}</AlertTitle>
|
||||
<AlertDescription>{schedulerStatusError}</AlertDescription>
|
||||
</Alert>
|
||||
) : null}
|
||||
{isLive && schedulerStatusReceivedAt ? <p className="text-xs text-muted-foreground">Статус получен: {new Date(schedulerStatusReceivedAt).toLocaleString("ru-RU")}</p> : null}
|
||||
{isLive && collectorError && (
|
||||
<Alert variant="destructive">
|
||||
<AlertCircleIcon />
|
||||
|
||||
Reference in new issue
Block a user