Sygnal startu nagrywania idzie przez konsole, nie przez funkcje
Deploy PROD / deploy (push) Successful in 25s

KAZDE nagranie konczylo sie bledem 412 "Start signal not received" po okolo
minucie, przy poprawnie dzialajacym pokoju, szablonie osiagalnym po sieci
Dockera i wlasciwych danych MinIO.

Szablon wolal `window.START_RECORDING()`, czyli funkcje, ktorej nikt nigdy nie
przypisywal. Byla zadeklarowana wylacznie w `declare global` jako opcjonalna,
wiec warunek `tracks.length > 0 && window.START_RECORDING` byl ZAWSZE falszywy.
Nawet gdyby nie byl, wywolanie funkcji niczego by nie dalo.

Egress czyta **wyjscie konsoli przegladarki** i czeka na napis
`START_RECORDING`. Dziala bez interfejsu, wiec konsola jest jedynym kanalem,
ktorym strona moze cokolwiek powiedziec procesowi nadrzednemu. Mowi o tym
dokumentacja LiveKit: "The recorder waits for the page to log START_RECORDING
to the console".

`console.log` nie jest tu wiec debugowaniem i nie wolno go usunac przy
porzadkowaniu logow. Sprawdzone, ze napis przezywa minifikacje produkcyjna:
minifikator Vite domyslnie nie wycina `console.log`.

Powtorne wyslanie blokuje `useRef`, a nie kasowanie pola `window`.

Diagnoza zajela dluzej, bo objaw myli: zadanie dociera do Egressu i przechodzi
walidacje, kontener laczy sie z Redisem, szablon odpowiada HTTP 200, a Egress
wchodzi do pokoju i widnieje na liscie uczestnikow. Wszystko poza jedna linia
dziala.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 13:31:33 +02:00
parent 2c3fbc6236
commit 2e1cb89fc6
+26 -19
View File
@@ -1,7 +1,7 @@
import '@livekit/components-styles' import '@livekit/components-styles'
import { GridLayout, LiveKitRoom, ParticipantTile, RoomAudioRenderer, useTracks } from '@livekit/components-react' import { GridLayout, LiveKitRoom, ParticipantTile, RoomAudioRenderer, useTracks } from '@livekit/components-react'
import { RoomEvent, Track } from 'livekit-client' import { RoomEvent, Track } from 'livekit-client'
import { useEffect } from 'react' import { useEffect, useRef } from 'react'
import { useSearchParams } from 'react-router-dom' import { useSearchParams } from 'react-router-dom'
/** /**
@@ -22,25 +22,29 @@ import { useSearchParams } from 'react-router-dom'
* Wlasny szablon lezy w naszym froncie i jest osiagalny po sieci Dockera, * Wlasny szablon lezy w naszym froncie i jest osiagalny po sieci Dockera,
* wiec nagrywanie dziala tak samo w sieci zamknietej. * wiec nagrywanie dziala tak samo w sieci zamknietej.
* *
* SYGNAL STARTU I KONCA * SYGNAL STARTU IDZIE PRZEZ KONSOLE PRZEGLADARKI
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* Egress czeka na `window.START_RECORDING()`, zanim zacznie pisac plik, i na * **Egress czyta konsole i szuka w niej napisu `START_RECORDING`.** Nie jest
* `window.END_RECORDING()`, zeby go domknac. **Bez wywolania pierwszej funkcji * to wywolanie funkcji: przegladarka Egress dziala bez interfejsu, a jedynym
* nagranie jest przerywane po kilkunastu sekundach** z bledem 412. Wolamy ja, * kanalem, ktorym strona moze cokolwiek powiedziec procesowi nadrzednemu, jest
* gdy pokoj jest polaczony i sa w nim jakies sciezki: nagranie ma zaczynac sie * wlasnie wyjscie konsoli. Analogicznie `END_RECORDING` domyka plik, choc przy
* od obrazu, a nie od pustej planszy. * zatrzymaniu z panelu robi to juz API (`StopEgress`).
*
* Wczesniejsza wersja wolala `window.START_RECORDING()`, czyli funkcje, ktorej
* nikt nigdy nie przypisywal: warunek `&& window.START_RECORDING` byl zawsze
* falszywy, a nawet gdyby nie byl, wywolanie funkcji niczego nie wypisuje.
* **Kazde nagranie konczylo sie przez to bledem 412 "Start signal not
* received"** po okolo minucie, przy poprawnie dzialajacym pokoju, szablonie
* osiagalnym po sieci Dockera i wlasciwych danych MinIO. Objaw myli, bo
* wszystko poza jedna linia dziala.
*
* Sygnal idzie, gdy pokoj jest polaczony i sa w nim jakies sciezki: nagranie
* ma zaczynac sie od obrazu, a nie od pustej planszy.
* *
* Ta strona nie jest dla ludzi: nie ma tu panelu interakcji, banerow ani * Ta strona nie jest dla ludzi: nie ma tu panelu interakcji, banerow ani
* paska akcji. Ma pokazywac obraz spotkania i nic wiecej. * paska akcji. Ma pokazywac obraz spotkania i nic wiecej.
*/ */
declare global {
interface Window {
START_RECORDING?: () => void
END_RECORDING?: () => void
}
}
export function RecordingTemplate() { export function RecordingTemplate() {
const [params] = useSearchParams() const [params] = useSearchParams()
const url = params.get('url') ?? '' const url = params.get('url') ?? ''
@@ -79,13 +83,16 @@ function RecordingStage() {
* Sygnal startu wysylamy raz, gdy pojawi sie pierwsza sciezka. Wyslanie go * Sygnal startu wysylamy raz, gdy pojawi sie pierwsza sciezka. Wyslanie go
* od razu po polaczeniu dawaloby kilka sekund czarnego obrazu na poczatku * od razu po polaczeniu dawaloby kilka sekund czarnego obrazu na poczatku
* kazdego nagrania. * kazdego nagrania.
*
* `console.log` nie jest tu debugowaniem, tylko JEDYNYM kanalem rozmowy
* z Egress: proces nadrzedny czyta wyjscie konsoli przegladarki i czeka
* dokladnie na ten napis. Nie usuwac przy porzadkowaniu logow.
*/ */
const started = useRef(false)
useEffect(() => { useEffect(() => {
if (tracks.length > 0 && window.START_RECORDING) { if (tracks.length > 0 && !started.current) {
window.START_RECORDING() started.current = true
// wolamy tylko raz: powtorne wywolanie Egress ignoruje, ale nie ma console.log('START_RECORDING')
// powodu go zasypywac przy kazdej zmianie liczby sciezek
window.START_RECORDING = undefined
} }
}, [tracks.length]) }, [tracks.length])