Stop the voice-queue poller when the payload is not what it expects

pollVoiceQueue began with 'if (!s || !s.items) return;'. On an unexpected
payload that returned before the code that clears the interval, so a page
left open polled /api/voices/queue every 2s forever. The web log shows 626
such polls - about 21 minutes of continuous requests from a browser through
the Caddy proxy, with CLOSE_WAIT sockets accumulating alongside.

An unexpected response now stops the poll rather than skipping the check.
Verified in a real browser against a deliberately malformed payload: one
request, then stopped, where it previously never stopped.
This commit is contained in:
B.D. Murphy
2026-10-11 20:58:52 -07:00
parent 9328159ec1
commit 4ac0388d7b

View File

@@ -358,6 +358,13 @@ function applyQueueState(name, status, error) {
var _vqPoll = null;
function stopVoiceQueuePolling() {
if (_vqPoll) {
clearInterval(_vqPoll);
_vqPoll = null;
}
}
function startVoiceQueuePolling() {
if (_vqPoll) return;
_vqPoll = setInterval(pollVoiceQueue, 2000);
@@ -366,7 +373,13 @@ function startVoiceQueuePolling() {
function pollVoiceQueue() {
fetch('/api/voices/queue').then(function(r) { return r.json(); }).then(function(s) {
if (!s || !s.items) return;
// An unexpected payload must STOP the poll, not skip the check. The
// bare return that used to be here left the interval running forever,
// so a page left open hit /api/voices/queue every 2s indefinitely.
if (!s || !Array.isArray(s.items)) {
stopVoiceQueuePolling();
return;
}
var anyPending = false;
s.items.forEach(function(item) {
applyQueueState(item.speaker_name, item.status, item.error || '');
@@ -374,9 +387,8 @@ function pollVoiceQueue() {
});
// Stop polling once nothing is outstanding, and refresh the list so the
// new audio file / voice badge appears without a manual reload.
if (!anyPending && _vqPoll) {
clearInterval(_vqPoll);
_vqPoll = null;
if (!anyPending) {
stopVoiceQueuePolling();
refreshSpeakerRow(null);
}
}).catch(function() {});