mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-10-03 16:05:24 -04:00
Montage review created 86 stream connkeys in five minutes while only two of them were ever polled, and each stream painted a single frame before being replaced about 1.3s later. The status poll for a connkey whose zms had exited returned result=Error, recover() restarted the stream under a new connkey, and the reply already queued for the old one arrived afterwards and restarted the new stream too. Every restart painted its first frame, which reset consecutiveErrors and recoveryDelay in img.onload, so the backoff never grew and the attempt limit was never reached. - Tag each ajax/stream.php exchange with the connkey it was issued for and ignore a reply, success or failure, once that connkey has been replaced. stream.php does not echo the connkey back, so the client tracks it. - Restart only on reason=no_socket, the one class that means zms is gone, matching streamErrorIsFatal() in MonitorStream.js. The helper is duplicated as EventStream.errorIsFatal() because montagereview.php does not load MonitorStream.js. - Start the poll timer next to the src that created the connkey instead of in img.onload, which is not a dependable per-restart signal for a multipart/x-mixed-replace img, and let the first query wait a full interval so a stream that is still starting is not read as a missing socket. - Reset the recovery counters only on a successful status reply, so the exponential backoff and the attempt limit both work. Also stop appending a second '?' to UrlToZMS, which already carries '?monitor=N', so the logs no longer show monitor=24?source=event. tests/js/eventstream-connkey.test.js covers the stale-reply rules, the fatal classification and the URL separator. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019YEe1M3PWVMqYWihUeAa5N