Fix accidental spinloop in connection accept logic#1979
Merged
rukai merged 2 commits intoshotover:mainfrom Mar 1, 2026
Merged
Conversation
tharinduamila-insta
approved these changes
Mar 1, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
During implementation of the hot reload functionality, a spin loop was accidentally introduced into the connection acception loop.
This does not impact shotovers ability to function, as evidenced by all the tests continuing to pass, but it is a huge performance concern as 1 CPU core will always be spent in a loop.
I discovered the problem because the connection IDs were jumping to ridiculously high values in the integration tests. Here you can see a connection ID of 12787950, which implies that 12787950 connections have been made during this test.
When in reality a driver will only make ~10 connections during a lengthy test.
Cause
The loop is this one here:
shotover-proxy/shotover/src/server.rs
Line 204 in 7a7f863
The tokio select found here, will wait until either:
However when hot reload is disabled (the default configuration) the
hot_reload_rxchannel is closed, and so the hot reload branch of the select will always immediately trigger. When the hot reload branch triggers, nothing happens, the loop ends, and starts from the beginning again.Why is hot_reload_rx closed?
The other end of the
hot_reload_rxis thehot_reload_tx, which is stored in Source:shotover-proxy/shotover/src/sources/mod.rs
Lines 37 to 42 in 7a7f863
Source::into_join_handleconsumes the Source, dropping everything inside the Source, except for the join_handle which is returned. You can tell it consumesSourcebecause the method argument isselfinstead of&self. see: https://google.github.io/comprehensive-rust/methods-and-traits/methods.htmlshotover-proxy/shotover/src/sources/mod.rs
Lines 59 to 61 in 7a7f863
As a result, hot_reload_tx is dropped during shotover setup, closing the channel.
The fix
The fix is subtle, but the goal here is to ensure that the
hot_reload_txremains alive for as long as the listener background task is alive.We do this by changing the into_join_handle into an async method, this ensures that the rest of Source is kept alive for the lifetime of the listener task.
Technically the
std::mem::drop(self.hot_reload_tx);isnt required, since the drop would occur implicitly at the end of the function, but since this issue is subtle, I figure its better to be explicit here.