@@ -158,9 +158,9 @@ impl DockerSandbox {
158158 return ;
159159 }
160160
161- // Start server in background
161+ // Start server in background (use -u for unbuffered stdout so log is readable)
162162 let start = self
163- . exec ( "nohup python3 /tools/server.py --cwd /repo > /tools/server.log 2>&1 &" , 5_000 )
163+ . exec ( "nohup python3 -u /tools/server.py --cwd /repo > /tools/server.log 2>&1 &" , 5_000 )
164164 . await ;
165165 if start. exit_code != 0 {
166166 tracing:: warn!(
@@ -170,18 +170,40 @@ impl DockerSandbox {
170170 ) ;
171171 }
172172
173- // Wait for health check (up to 3 seconds)
174- for _ in 0 ..6 {
175- let health = self
176- . exec ( "curl -sf http://localhost:8080/health 2>/dev/null || python3 -c \" import urllib.request; urllib.request.urlopen('http://localhost:8080/health')\" 2>/dev/null" , 2_000 )
177- . await ;
178- if health. exit_code == 0 {
179- tracing:: debug!( container = %self . container_name, "Tool server healthy" ) ;
173+ // Health check: use python3 urllib (curl is not installed in slim images)
174+ for attempt in 0 ..6 {
175+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) . await ;
176+ let health = self . tool_server_health ( ) . await ;
177+ if health {
178+ tracing:: debug!( container = %self . container_name, attempt = attempt, "Tool server healthy" ) ;
180179 return ;
181180 }
182- tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) . await ;
183181 }
184- tracing:: warn!( container = %self . container_name, "Tool server health check failed, tools may not work" ) ;
182+ // Log server output for debugging
183+ let log = self . exec ( "cat /tools/server.log 2>/dev/null" , 5_000 ) . await ;
184+ tracing:: warn!(
185+ container = %self . container_name,
186+ server_log = %log. stdout,
187+ "Tool server health check failed after 3s, tools may not work"
188+ ) ;
189+ }
190+
191+ /// Check if the tool server is healthy via python3 urllib inside the container.
192+ async fn tool_server_health ( & self ) -> bool {
193+ let result = tokio:: time:: timeout (
194+ std:: time:: Duration :: from_millis ( 2_000 ) ,
195+ Command :: new ( "docker" )
196+ . args ( [
197+ "exec" , "-w" , "/repo" , & self . container_name ,
198+ "python3" , "-c" ,
199+ "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')" ,
200+ ] )
201+ . stdout ( Stdio :: null ( ) )
202+ . stderr ( Stdio :: null ( ) )
203+ . status ( ) ,
204+ )
205+ . await ;
206+ matches ! ( result, Ok ( Ok ( status) ) if status. success( ) )
185207 }
186208
187209 /// Call a tool on the HTTP tool server running inside the container.
0 commit comments