fix and update

This commit is contained in:
lendry
2026-06-30 23:18:53 +03:00
parent 6ee3ffe0a5
commit 4b2ade9354
6 changed files with 17 additions and 41 deletions

View File

@@ -142,7 +142,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
}
const onReady = () => setIsApiReady(true);
const onNotReady = () => {
setIsApiReady(false);
if (!initialBootstrapDoneRef.current) {
setIsApiReady(false);
}
};
const unsubReady = subscribeApiReady(onReady);
const unsubNotReady = subscribeApiNotReady(onNotReady);

View File

@@ -1,7 +1,7 @@
'use client';
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { apiFetch, ensureApiGatewayReady, isApiGatewayReady, subscribeApiReady } from '@/lib/api';
import { apiFetch } from '@/lib/api';
interface PublicSettingsContextValue {
projectName: string;
@@ -27,7 +27,6 @@ export function PublicSettingsProvider({ children }: { children: React.ReactNode
const refreshPublicSettings = useCallback(async () => {
try {
await ensureApiGatewayReady();
const response = await apiFetch<{ settings: Array<{ key: string; value: string }> }>('/settings/public');
const map = Object.fromEntries((response.settings ?? []).map((item) => [item.key, item.value]));
setSettings(map);
@@ -39,13 +38,7 @@ export function PublicSettingsProvider({ children }: { children: React.ReactNode
}, []);
useEffect(() => {
if (isApiGatewayReady()) {
void refreshPublicSettings();
return;
}
return subscribeApiReady(() => {
void refreshPublicSettings();
});
void refreshPublicSettings();
}, [refreshPublicSettings]);
const value = useMemo(

View File

@@ -2,7 +2,7 @@
import * as React from 'react';
import { useAuth } from '@/components/id/auth-provider';
import { ensureApiGatewayReady, fetchUnreadNotificationCount, getWsUrl, type ChatMessage } from '@/lib/api';
import { fetchUnreadNotificationCount, getWsUrl, type ChatMessage } from '@/lib/api';
import { dispatchAvatarUpdated, dispatchChatRoomAvatarUpdated } from '@/lib/avatar-events';
const WS_RECONNECT_BASE_MS = 2_000;
@@ -90,13 +90,6 @@ export function RealtimeProvider({ children }: { children: React.ReactNode }) {
}
async function connect() {
if (cancelled) return;
try {
await ensureApiGatewayReady();
} catch {
scheduleReconnect();
return;
}
if (cancelled) return;
const url = `${getWsUrl()}?token=${encodeURIComponent(token!)}`;
const socket = new WebSocket(url);

View File

@@ -545,9 +545,6 @@ export async function refreshAuthSession(): Promise<RefreshSessionResponse> {
export async function syncFedcmSession(accessToken?: string | null) {
const token = resolveAccessToken(accessToken);
if (typeof window === 'undefined' || !token) return;
if (!isApiGatewayReady()) {
await ensureApiGatewayReady();
}
try {
await apiFetch<{ synced: boolean }>(
'/fedcm/session/sync',
@@ -680,7 +677,7 @@ export function buildSystemSettingPayload(setting: Pick<SystemSetting, 'key' | '
}
const GATEWAY_RETRY_STATUS = new Set([502, 503, 504]);
const GATEWAY_RETRY_ATTEMPTS = 6;
const GATEWAY_RETRY_ATTEMPTS = 4;
const GATEWAY_STABLE_PROBE_INTERVAL_MS = 800;
const GATEWAY_STABLE_MAX_ROUNDS = 8;
const API_MAX_CONCURRENT = 6;
@@ -833,7 +830,7 @@ function gatewayRetryDelay(attempt: number): number {
return 800 + attempt * 700;
}
/** Повтор при кратковременном 502/503/504 (nginx не достучался до api-gateway после перезапуска). */
/** Повтор при кратковременном 502/503/504 без сброса всего UI в bootstrap. */
async function fetchWithGatewayRetry(url: string, init: RequestInit): Promise<Response> {
let lastNetworkError: unknown;
for (let attempt = 0; attempt < GATEWAY_RETRY_ATTEMPTS; attempt++) {
@@ -843,24 +840,14 @@ async function fetchWithGatewayRetry(url: string, init: RequestInit): Promise<Re
markApiGatewayReady();
}
if (GATEWAY_RETRY_STATUS.has(response.status) && attempt + 1 < GATEWAY_RETRY_ATTEMPTS) {
invalidateApiGatewayReady();
try {
await ensureApiGatewayReady(true);
} catch {
await sleep(gatewayRetryDelay(attempt));
}
await sleep(gatewayRetryDelay(attempt));
continue;
}
return response;
} catch (error) {
lastNetworkError = error;
if (attempt + 1 < GATEWAY_RETRY_ATTEMPTS) {
invalidateApiGatewayReady();
try {
await ensureApiGatewayReady(true);
} catch {
await sleep(gatewayRetryDelay(attempt));
}
await sleep(gatewayRetryDelay(attempt));
continue;
}
throw mapFetchError(error);

View File

@@ -1,5 +1,3 @@
import { ensureApiGatewayReady } from '@/lib/api';
const GATEWAY_RETRY_STATUS = new Set([502, 503, 504]);
const MEDIA_FETCH_MAX_ATTEMPTS = 8;
const MEDIA_SLOW_LOAD_WARN_MS = 8_000;
@@ -45,7 +43,6 @@ export async function fetchMediaBlobWithRetry(
for (let attempt = 0; attempt < MEDIA_FETCH_MAX_ATTEMPTS; attempt += 1) {
try {
await ensureApiGatewayReady();
const response = await fetch(mediaUrl, {
headers: { Authorization: `Bearer ${token}` },
cache: 'no-store'

View File

@@ -2120,7 +2120,7 @@ nginx_proxy_headers=" proxy_set_header Host \$host;
proxy_set_header X-Forwarded-Host \$host;
proxy_set_header Authorization \$http_authorization;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;"
proxy_connect_timeout 5s;"
# API upstream: keepalive вместо Connection: close — иначе лавина параллельных запросов SPA даёт 502.
nginx_proxy_headers_api=" proxy_set_header Host \$host;
@@ -2132,7 +2132,9 @@ nginx_proxy_headers_api=" proxy_set_header Host \$host;
proxy_http_version 1.1;
proxy_set_header Connection \"\";
proxy_read_timeout 300s;
proxy_connect_timeout 75s;"
proxy_connect_timeout 5s;
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 3;"
# proxy_pass к корню апстрима БЕЗ $request_uri — иначе nginx считает директиву
# «variable proxy_pass» и требует resolver (502: no resolver defined to resolve lendry-id-frontend).
@@ -2390,7 +2392,9 @@ ${proxy_ws}
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_read_timeout 86400s;
proxy_connect_timeout 75s;
proxy_connect_timeout 5s;
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 3;
}
location ^~ /idp-api/ {