@@ -47,6 +47,8 @@ use crate::{
4747 Body , NotFoundRouteKind , TlsConfig , TriggerApp , TriggerInstanceBuilder ,
4848} ;
4949
50+ pub const MAX_RETRIES : u16 = 10 ;
51+
5052/// An HTTP server which runs Spin apps.
5153pub struct HttpServer < F : RuntimeFactors > {
5254 /// The address the server is listening on.
@@ -148,44 +150,16 @@ impl<F: RuntimeFactors> HttpServer<F> {
148150
149151 /// Serve incoming requests over the provided [`TcpListener`].
150152 pub async fn serve ( self : Arc < Self > ) -> anyhow:: Result < ( ) > {
151- let listener: TcpListener = match TcpListener :: bind ( self . listen_addr ) . await {
152- Ok ( listener) => listener,
153- Err ( err) => {
154- if self . find_free_port && err. kind ( ) == ErrorKind :: AddrInUse {
155- let mut found_listener = None ;
156- let mut addr = self . listen_addr ;
157- for _ in 1 ..=9 {
158- if addr. port ( ) == u16:: MAX {
159- anyhow:: bail!(
160- "Couldn't find a free port as we've reached the maximum port number. Consider retrying with a lower base port."
161- ) ;
162- }
163-
164- addr. set_port ( addr. port ( ) + 1 ) ;
165-
166- match TcpListener :: bind ( addr) . await {
167- Ok ( listener) => {
168- found_listener = Some ( listener) ;
169- break ;
170- }
171- Err ( err) => {
172- if err. kind ( ) == ErrorKind :: AddrInUse {
173- continue ;
174- }
175- anyhow:: bail!( "Unable to listen on {}" , self . listen_addr) ;
176- }
177- }
178- }
179-
180- found_listener. ok_or_else ( || anyhow:: anyhow!(
181- "Couldn't find a free port in the range {}-{}. Consider retrying with a different base port." ,
182- self . listen_addr. port( ) ,
183- self . listen_addr. port( ) + 9
184- ) ) ?
153+ let listener: TcpListener = if self . find_free_port {
154+ self . search_for_free_port ( ) . await ?
155+ } else {
156+ TcpListener :: bind ( self . listen_addr ) . await . map_err ( |err| {
157+ if err. kind ( ) == ErrorKind :: AddrInUse {
158+ anyhow:: anyhow!( "Unable to listen on {}. To have Spin search for a free port, use the --find-free-port option." , self . listen_addr)
185159 } else {
186- anyhow:: bail !( "Unable to listen on {}. To have Spin search for a free port, use the --find-free-port option. " , self . listen_addr)
160+ anyhow:: anyhow !( "Unable to listen on {}" , self . listen_addr)
187161 }
188- }
162+ } ) ?
189163 } ;
190164
191165 if let Some ( tls_config) = self . tls_config . clone ( ) {
@@ -196,6 +170,36 @@ impl<F: RuntimeFactors> HttpServer<F> {
196170 Ok ( ( ) )
197171 }
198172
173+ async fn search_for_free_port ( & self ) -> anyhow:: Result < TcpListener > {
174+ let mut found_listener = None ;
175+ let mut addr = self . listen_addr ;
176+
177+ for _ in 1 ..=MAX_RETRIES {
178+ if addr. port ( ) == u16:: MAX {
179+ anyhow:: bail!(
180+ "Couldn't find a free port as we've reached the maximum port number. Consider retrying with a lower base port."
181+ ) ;
182+ }
183+
184+ addr. set_port ( addr. port ( ) + 1 ) ;
185+
186+ match TcpListener :: bind ( addr) . await {
187+ Ok ( listener) => {
188+ found_listener = Some ( listener) ;
189+ break ;
190+ }
191+ Err ( err) if err. kind ( ) == ErrorKind :: AddrInUse => continue ,
192+ Err ( err) => anyhow:: bail!( "Unable to listen on {addr}: {err:?}" , ) ,
193+ }
194+ }
195+
196+ found_listener. ok_or_else ( || anyhow:: anyhow!(
197+ "Couldn't find a free port in the range {}-{}. Consider retrying with a different base port." ,
198+ self . listen_addr. port( ) ,
199+ self . listen_addr. port( ) + MAX_RETRIES
200+ ) )
201+ }
202+
199203 async fn serve_http ( self : Arc < Self > , listener : TcpListener ) -> anyhow:: Result < ( ) > {
200204 self . print_startup_msgs ( "http" , & listener) ?;
201205 loop {
0 commit comments