1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-14 17:22:20 +01:00

Fix slow noise handshake by reading multiple messages per loop

This commit is contained in:
J. Nick Koston
2025-06-18 18:36:55 +02:00
parent 6667336bd8
commit 3f71c09b7b

View File

@@ -28,6 +28,12 @@
namespace esphome { namespace esphome {
namespace api { namespace api {
// Read a maximum of 5 messages per loop iteration to prevent starving other components.
// This is a balance between API responsiveness and allowing other components to run.
// Since each message could contain multiple protobuf messages when using packet batching,
// this limits the number of messages processed, not the number of TCP packets.
static constexpr uint8_t MAX_MESSAGES_PER_LOOP = 5;
static const char *const TAG = "api.connection"; static const char *const TAG = "api.connection";
static const int ESP32_CAMERA_STOP_STREAM = 5000; static const int ESP32_CAMERA_STOP_STREAM = 5000;
@@ -109,12 +115,16 @@ void APIConnection::loop() {
return; return;
} }
const uint32_t now = App.get_loop_component_start_time();
// Check if socket has data ready before attempting to read // Check if socket has data ready before attempting to read
if (this->helper_->is_socket_ready()) { if (this->helper_->is_socket_ready()) {
// Read up to MAX_MESSAGES_PER_LOOP messages per loop to improve throughput
for (uint8_t message_count = 0; message_count < MAX_MESSAGES_PER_LOOP; message_count++) {
ReadPacketBuffer buffer; ReadPacketBuffer buffer;
err = this->helper_->read_packet(&buffer); err = this->helper_->read_packet(&buffer);
if (err == APIError::WOULD_BLOCK) { if (err == APIError::WOULD_BLOCK) {
// pass // No more data available
break;
} else if (err != APIError::OK) { } else if (err != APIError::OK) {
on_fatal_error(); on_fatal_error();
if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) { if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) {
@@ -127,7 +137,7 @@ void APIConnection::loop() {
} }
return; return;
} else { } else {
this->last_traffic_ = App.get_loop_component_start_time(); this->last_traffic_ = now;
// read a packet // read a packet
if (buffer.data_len > 0) { if (buffer.data_len > 0) {
this->read_message(buffer.data_len, buffer.type, &buffer.container[buffer.data_offset]); this->read_message(buffer.data_len, buffer.type, &buffer.container[buffer.data_offset]);
@@ -138,6 +148,7 @@ void APIConnection::loop() {
return; return;
} }
} }
}
// Process deferred batch if scheduled // Process deferred batch if scheduled
if (this->deferred_batch_.batch_scheduled && if (this->deferred_batch_.batch_scheduled &&
@@ -152,7 +163,6 @@ void APIConnection::loop() {
static uint8_t max_ping_retries = 60; static uint8_t max_ping_retries = 60;
static uint16_t ping_retry_interval = 1000; static uint16_t ping_retry_interval = 1000;
const uint32_t now = App.get_loop_component_start_time();
if (this->sent_ping_) { if (this->sent_ping_) {
// Disconnect if not responded within 2.5*keepalive // Disconnect if not responded within 2.5*keepalive
if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) { if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) {