fix(install,e2e): установка на VPS владельца — четыре дефекта шаблонов и хелперов
Установка на VPS (Debian 13, 1 vCPU/2 ГБ) с внешним прокси на том же хосте
вскрыла дефекты, которые не проявлялись на стенде:
- compose: с --no-turn порты TURN всё равно публиковались, и стек не стартовал
(«failed to bind host port 0.0.0.0:3478/udp» — порт держит чужой coturn).
Теперь строки портов TURN подставляет установщик (GLCHAT_TURN_PORTS).
- LiveKit: добавлен отдельный адрес публикации медиапортов
(--livekit-media-bind-addr / GLCHAT_LIVEKIT_MEDIA_BIND): сигналинг остаётся
внутренним для прокси, а 7881/tcp и 7882/udp доступны клиентам из интернета.
- external-proxy.conf: адреса апстримов берутся из фактической привязки
(--app-bind-addr/--livekit-bind-addr), а не жёсткого 127.0.0.1.
- при --no-files-subdomain шаблоны внешнего прокси и встроенного Caddy писали
два блока с одним адресом сайта (Caddy отвергает такой конфиг и в embedded
режиме установка ломалась целиком): блок пользовательского контента теперь
появляется только при отдельном домене (GLCHAT_FILES_BLOCK).
- e2e: postWithRetry/repeat429 читают retry_after_ms из конверта ошибки
({"error":{...}}) — без этого хелперы сдавались раньше, чем сервер разрешал
повтор, и регистрация пробных аккаунтов на свежем инстансе падала.
- e2e: voice.spec.ts ищет комнату «Голос» точным именем: пока сайдбар
дорисовывает сервер, видны комнаты предыдущего («Голос A»/«Голос B»).
This commit is contained in:
+22
-5
@@ -63,12 +63,22 @@ export async function postWithRetry(
|
||||
api: APIRequestContext,
|
||||
path: string,
|
||||
data: Record<string, unknown>,
|
||||
attempts = 6,
|
||||
attempts = 8,
|
||||
): Promise<Awaited<ReturnType<APIRequestContext['post']>>> {
|
||||
let response = await api.post(path, { data });
|
||||
for (let attempt = 1; attempt < attempts && response.status() === 429; attempt += 1) {
|
||||
const payload = (await response.json().catch(() => ({}))) as { retry_after_ms?: number };
|
||||
const wait = Math.min(Math.max(payload.retry_after_ms ?? 1_000, 500), 20_000);
|
||||
// Пауза лежит в конверте ошибки (§8.5: {"error":{"retry_after_ms":…}}), а не
|
||||
// в корне тела: без `error` хелпер ждал фиксированную секунду и сдавался
|
||||
// раньше, чем сервер разрешал повтор — на свежем инстансе регистрация
|
||||
// пробных аккаунтов из-за этого падала (VPS, 27.09.2026).
|
||||
const payload = (await response.json().catch(() => ({}))) as {
|
||||
retry_after_ms?: number;
|
||||
error?: { retry_after_ms?: number };
|
||||
};
|
||||
const wait = Math.min(
|
||||
Math.max(payload.error?.retry_after_ms ?? payload.retry_after_ms ?? 1_000, 500),
|
||||
20_000,
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, wait + 200));
|
||||
response = await api.post(path, { data });
|
||||
}
|
||||
@@ -359,9 +369,16 @@ export async function repeat429(
|
||||
): Promise<APIResponse> {
|
||||
let response = await request();
|
||||
for (let attempt = 1; attempt < attempts && response.status() === 429; attempt += 1) {
|
||||
const payload = (await response.json().catch(() => ({}))) as { retry_after_ms?: number };
|
||||
const payload = (await response.json().catch(() => ({}))) as {
|
||||
retry_after_ms?: number;
|
||||
error?: { retry_after_ms?: number };
|
||||
};
|
||||
// Ждём столько, сколько просит сервер: лимит — 120 запросов в минуту.
|
||||
const wait = Math.min(Math.max(payload.retry_after_ms ?? 1_000, 1_000), 30_000);
|
||||
// Пауза лежит в конверте ошибки (§8.5), поэтому читаем и `error`.
|
||||
const wait = Math.min(
|
||||
Math.max(payload.error?.retry_after_ms ?? payload.retry_after_ms ?? 1_000, 1_000),
|
||||
30_000,
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, wait + 250));
|
||||
response = await request();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user