Fix web_server busy loop with ungracefully disconnected clients (#9312)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
J. Nick Koston 2025-07-03 21:07:25 -05:00 committed by GitHub
parent adb7ccdbc7
commit d686257cff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 13 additions and 0 deletions

View File

@ -125,7 +125,16 @@ void DeferredUpdateEventSource::process_deferred_queue_() {
if (this->send(message.c_str(), "state") != DISCARDED) {
// O(n) but memory efficiency is more important than speed here which is why std::vector was chosen
deferred_queue_.erase(deferred_queue_.begin());
this->consecutive_send_failures_ = 0; // Reset failure count on successful send
} else {
this->consecutive_send_failures_++;
if (this->consecutive_send_failures_ >= MAX_CONSECUTIVE_SEND_FAILURES) {
// Too many failures, connection is likely dead
ESP_LOGW(TAG, "Closing stuck EventSource connection after %" PRIu16 " failed sends",
this->consecutive_send_failures_);
this->close();
this->deferred_queue_.clear();
}
break;
}
}
@ -164,6 +173,8 @@ void DeferredUpdateEventSource::deferrable_send_state(void *source, const char *
std::string message = message_generator(web_server_, source);
if (this->send(message.c_str(), "state") == DISCARDED) {
deq_push_back_with_dedup_(source, message_generator);
} else {
this->consecutive_send_failures_ = 0; // Reset failure count on successful send
}
}
}

View File

@ -127,6 +127,8 @@ class DeferredUpdateEventSource : public AsyncEventSource {
// footprint is more important than speed here)
std::vector<DeferredEvent> deferred_queue_;
WebServer *web_server_;
uint16_t consecutive_send_failures_{0};
static constexpr uint16_t MAX_CONSECUTIVE_SEND_FAILURES = 2500; // ~20 seconds at 125Hz loop rate
// helper for allowing only unique entries in the queue
void deq_push_back_with_dedup_(void *source, message_generator_t *message_generator);