Skip to content

GET /api/schemes returns incomplete list during startup (race condition) #2088

@twhittock

Description

@twhittock

Problem

GET /api/schemes returns an incomplete list of supported schemes when called shortly after go2rtc starts. The root cause is a race between the HTTP server binding its socket and the remaining modules registering their schemes.

The startup sequence in main.go is:

1. api.Init()     ← HTTP server binds and starts listening HERE
                    logs: "INF [api] listen addr=..."
2. ws.Init()
3. streams.Init() ← /api/schemes endpoint registered here
4. http.Init()    ← "http"/"https" schemes registered
5. rtsp.Init()    ← "rtsp"/"rtsps" schemes registered
6. webrtc.Init()  ← "webrtc" scheme registered
7. ffmpeg.Init()  ← "ffmpeg" scheme registered
   ...and so on

Any client that queries /api/schemes between step 1 and the final module Init() will receive an incomplete — or in early steps, empty — scheme list.

Impact: Home Assistant integration

Home Assistant's go2rtc integration manages the go2rtc process and watches its stdout for the message "INF [api] listen addr=" to know when the server is ready (server.py:21, server.py:246-247).

This message is emitted in the listen() function — the moment the TCP socket binds, which happens inside api.Init() — the first module to be initialized. At this point, none of the stream-source modules have run yet.

Immediately after this message is seen, HA calls GET /api/schemes to build a cache of supported schemes. Because this call races with the remaining module initializations, the cache is frequently missing schemes like ffmpeg, webrtc, onvif, exec, and rtsp, causing valid stream sources to be incorrectly rejected.

Proposed fix

Add a GET /api/ready endpoint that returns 503 Service Unavailable while modules are still initializing, and 200 OK once all modules have completed their Init() calls. This would require:

  1. A readiness flag in the api package, set via an exported SetReady() function
  2. The readyHandler registered at api/ready in Init()
  3. A call to api.SetReady() in main.go after the module init loop completes

This gives clients a reliable readiness probe rather than relying on a log message that fires too early. It also doubles as a useful Docker/Kubernetes health check endpoint.

Happy to submit a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions