fix and update

This commit is contained in:
lendry
2026-06-30 15:36:07 +03:00
parent 879875508f
commit 69063c8fba
5 changed files with 97 additions and 155 deletions

View File

@@ -9,12 +9,12 @@ import { AppToastProvider } from '@/components/id/toast-provider';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<AppToastProvider>
<PublicSettingsProvider>
<ProjectHead />
<AuthProvider>
<AuthProvider>
<PublicSettingsProvider>
<ProjectHead />
<RealtimeProvider>{children}</RealtimeProvider>
</AuthProvider>
</PublicSettingsProvider>
</PublicSettingsProvider>
</AuthProvider>
</AppToastProvider>
);
}

View File

@@ -680,8 +680,6 @@ export function buildSystemSettingPayload(setting: Pick<SystemSetting, 'key' | '
const GATEWAY_RETRY_STATUS = new Set([502, 503, 504]);
const GATEWAY_RETRY_ATTEMPTS = 4;
const GATEWAY_PROBE_MAX_ATTEMPTS = 48;
const GATEWAY_PROBE_BASE_DELAY_MS = 450;
const GATEWAY_STABLE_PROBE_INTERVAL_MS = 800;
const GATEWAY_STABLE_MAX_ROUNDS = 18;
const API_MAX_CONCURRENT = 6;
@@ -696,6 +694,7 @@ function sleep(ms: number): Promise<void> {
let gatewayReadyResolved = false;
let gatewayReadyPromise: Promise<void> | null = null;
let stableGatewayPromise: Promise<void> | null = null;
let gatewayReadyAt = 0;
let activeApiRequests = 0;
const apiRequestWaiters: Array<() => void> = [];
@@ -703,11 +702,13 @@ const apiRequestWaiters: Array<() => void> = [];
export function resetApiGatewayWarmup() {
gatewayReadyResolved = false;
gatewayReadyPromise = null;
stableGatewayPromise = null;
}
export function invalidateApiGatewayReady() {
gatewayReadyResolved = false;
gatewayReadyAt = 0;
stableGatewayPromise = null;
if (typeof window !== 'undefined') {
window.dispatchEvent(new CustomEvent(API_NOT_READY_EVENT));
}
@@ -745,26 +746,34 @@ export function subscribeApiNotReady(listener: () => void): () => void {
/** Несколько подряд успешных /health через nginx — защита от «один OK, потом 502». */
export async function waitForStableGateway(stableProbes = 3): Promise<void> {
if (typeof window === 'undefined') return;
if (gatewayReadyResolved && stableProbes <= 1) return;
if (stableGatewayPromise) return stableGatewayPromise;
gatewayReadyResolved = false;
gatewayReadyAt = 0;
stableGatewayPromise = (async () => {
gatewayReadyResolved = false;
gatewayReadyAt = 0;
let streak = 0;
for (let attempt = 0; attempt < GATEWAY_STABLE_MAX_ROUNDS && streak < stableProbes; attempt += 1) {
if (await probeGatewayAlive()) {
streak += 1;
if (streak >= stableProbes) {
markApiGatewayReady();
return;
let streak = 0;
for (let attempt = 0; attempt < GATEWAY_STABLE_MAX_ROUNDS && streak < stableProbes; attempt += 1) {
if (await probeGatewayAlive()) {
streak += 1;
if (streak >= stableProbes) {
markApiGatewayReady();
return;
}
await sleep(GATEWAY_STABLE_PROBE_INTERVAL_MS);
} else {
streak = 0;
await sleep(Math.min(900 + attempt * 300, 2800));
}
await sleep(GATEWAY_STABLE_PROBE_INTERVAL_MS);
} else {
streak = 0;
await sleep(Math.min(900 + attempt * 300, 2800));
}
}
throw new ApiError('Сервер API временно недоступен. Попробуйте обновить страницу.', 503, 'GATEWAY_UNAVAILABLE');
throw new ApiError('Сервер API временно недоступен. Попробуйте обновить страницу.', 503, 'GATEWAY_UNAVAILABLE');
})().finally(() => {
stableGatewayPromise = null;
});
return stableGatewayPromise;
}
async function acquireApiSlot(): Promise<void> {
@@ -799,23 +808,7 @@ async function probeGatewayAlive(): Promise<boolean> {
}
}
async function waitForGatewayAlive(): Promise<void> {
if (gatewayReadyResolved) return;
for (let attempt = 0; attempt < GATEWAY_PROBE_MAX_ATTEMPTS; attempt += 1) {
if (await probeGatewayAlive()) {
markApiGatewayReady();
return;
}
if (attempt + 1 < GATEWAY_PROBE_MAX_ATTEMPTS) {
await sleep(Math.min(GATEWAY_PROBE_BASE_DELAY_MS + attempt * 280, 2800));
}
}
throw new ApiError('Сервер API временно недоступен. Попробуйте обновить страницу.', 503, 'GATEWAY_UNAVAILABLE');
}
/** Один общий прогрев: все apiFetch ждут успешный /health, без раннего «fail-open». */
/** Один общий прогрев: все apiFetch ждут стабильный /health через nginx. */
export async function ensureApiGatewayReady(force = false): Promise<void> {
if (typeof window === 'undefined') return;
if (gatewayReadyResolved && !force) return;
@@ -823,9 +816,12 @@ export async function ensureApiGatewayReady(force = false): Promise<void> {
if (force) {
gatewayReadyResolved = false;
gatewayReadyAt = 0;
stableGatewayPromise = null;
}
gatewayReadyPromise = waitForGatewayAlive().finally(() => {
const probes = force ? 2 : 1;
gatewayReadyPromise = waitForStableGateway(probes).finally(() => {
gatewayReadyPromise = null;
});
@@ -848,7 +844,7 @@ async function fetchWithGatewayRetry(url: string, init: RequestInit): Promise<Re
if (GATEWAY_RETRY_STATUS.has(response.status) && attempt + 1 < GATEWAY_RETRY_ATTEMPTS) {
invalidateApiGatewayReady();
try {
await waitForStableGateway(2);
await ensureApiGatewayReady(true);
} catch {
await sleep(gatewayRetryDelay(attempt));
}
@@ -860,7 +856,7 @@ async function fetchWithGatewayRetry(url: string, init: RequestInit): Promise<Re
if (attempt + 1 < GATEWAY_RETRY_ATTEMPTS) {
invalidateApiGatewayReady();
try {
await waitForStableGateway(2);
await ensureApiGatewayReady(true);
} catch {
await sleep(gatewayRetryDelay(attempt));
}