3131 create_koyeb_sandbox_routes ,
3232 create_sandbox_client ,
3333 get_api_client ,
34- is_sandbox_healthy ,
3534 logger ,
3635 run_sync_in_executor ,
3736 validate_port ,
@@ -80,15 +79,13 @@ def __init__(
8079 sandbox_id : str ,
8180 app_id : str ,
8281 service_id : str ,
83- instance_id : str ,
8482 name : Optional [str ] = None ,
8583 api_token : Optional [str ] = None ,
8684 sandbox_secret : Optional [str ] = None ,
8785 ):
8886 self .sandbox_id = sandbox_id
8987 self .app_id = app_id
9088 self .service_id = service_id
91- self .instance_id = instance_id
9289 self .name = name
9390 self .api_token = api_token
9491 self .sandbox_secret = sandbox_secret
@@ -224,41 +221,11 @@ def _create_sync(
224221 create_service = CreateService (app_id = app_id , definition = deployment_definition )
225222 service_response = services_api .create_service (service = create_service )
226223 service_id = service_response .service .id
227- deployment_id = service_response .service .latest_deployment_id
228-
229- deployments_api = DeploymentsApi (services_api .api_client )
230-
231- max_wait = min (timeout // 2 , 60 ) if timeout > 60 else timeout
232- wait_interval = 0.5
233- start_time = time .time ()
234-
235- while time .time () - start_time < max_wait :
236- try :
237- scaling_response = deployments_api .get_deployment_scaling (
238- id = deployment_id
239- )
240-
241- if scaling_response .replicas and scaling_response .replicas [0 ].instances :
242- instance_id = scaling_response .replicas [0 ].instances [0 ].id
243- break
244- else :
245- logger .debug (
246- f"Waiting for instances to be created... (elapsed: { time .time () - start_time :.1f} s)"
247- )
248- time .sleep (wait_interval )
249- except Exception as e :
250- logger .warning (f"Error getting deployment scaling: { e } " )
251- time .sleep (wait_interval )
252- else :
253- raise SandboxError (
254- f"No instances found in deployment after { max_wait } seconds"
255- )
256224
257225 return cls (
258226 sandbox_id = name ,
259227 app_id = app_id ,
260228 service_id = service_id ,
261- instance_id = instance_id ,
262229 name = name ,
263230 api_token = api_token ,
264231 sandbox_secret = sandbox_secret ,
@@ -314,7 +281,6 @@ def get_from_id(
314281 # Get deployment to extract sandbox_secret from env vars
315282 deployment_id = service .active_deployment_id or service .latest_deployment_id
316283 sandbox_secret = None
317- instance_id = None
318284
319285 if deployment_id :
320286 try :
@@ -329,36 +295,13 @@ def get_from_id(
329295 if env_var .key == "SANDBOX_SECRET" :
330296 sandbox_secret = env_var .value
331297 break
332-
333- # Get instance_id from deployment scaling
334- try :
335- scaling_response = deployments_api .get_deployment_scaling (
336- id = deployment_id
337- )
338- if (
339- scaling_response .replicas
340- and scaling_response .replicas [0 ].instances
341- and len (scaling_response .replicas [0 ].instances ) > 0
342- ):
343- instance_id = scaling_response .replicas [0 ].instances [0 ].id
344- except Exception :
345- logger .debug (
346- f"Could not get instance for deployment { deployment_id } "
347- )
348298 except Exception as e :
349299 logger .debug (f"Could not get deployment { deployment_id } : { e } " )
350300
351- if not instance_id :
352- raise SandboxError (
353- f"Could not find instance for sandbox { id } . "
354- "The sandbox may not be fully provisioned yet."
355- )
356-
357301 return cls (
358302 sandbox_id = service .id ,
359303 app_id = service .app_id ,
360304 service_id = service .id ,
361- instance_id = instance_id ,
362305 name = sandbox_name ,
363306 api_token = api_token ,
364307 sandbox_secret = sandbox_secret ,
@@ -391,12 +334,7 @@ def wait_ready(
391334 time .sleep (poll_interval )
392335 continue
393336
394- is_healthy = is_sandbox_healthy (
395- self .instance_id ,
396- sandbox_url = sandbox_url ,
397- sandbox_secret = self .sandbox_secret ,
398- api_token = self .api_token ,
399- )
337+ is_healthy = self .is_healthy ()
400338
401339 if is_healthy :
402340 return True
@@ -561,22 +499,25 @@ def _check_response_error(self, response: Dict, operation: str) -> None:
561499 error_msg = response .get ("error" , "Unknown error" )
562500 raise SandboxError (f"Failed to { operation } : { error_msg } " )
563501
564- def status (self ) -> str :
565- """Get current sandbox status"""
566- from .utils import get_sandbox_status
567-
568- status = get_sandbox_status (self .instance_id , self .api_token )
569- return status .value
570-
571502 def is_healthy (self ) -> bool :
572503 """Check if sandbox is healthy and ready for operations"""
573504 sandbox_url = self ._get_sandbox_url ()
574- return is_sandbox_healthy (
575- self .instance_id ,
576- sandbox_url = sandbox_url ,
577- sandbox_secret = self .sandbox_secret ,
578- api_token = self .api_token ,
579- )
505+ if not sandbox_url or not self .sandbox_secret :
506+ return False
507+
508+ # Check executor health directly - this is what matters for operations
509+ # If executor is healthy, the sandbox is usable (will wake up service if needed)
510+ try :
511+ from .executor_client import SandboxClient
512+
513+ client = SandboxClient (sandbox_url , self .sandbox_secret )
514+ health_response = client .health ()
515+ if isinstance (health_response , dict ):
516+ status = health_response .get ("status" , "" ).lower ()
517+ return status in ["ok" , "healthy" , "ready" ]
518+ return True # If we got a response, consider it healthy
519+ except Exception :
520+ return False
580521
581522 @property
582523 def filesystem (self ) -> "SandboxFilesystem" :
@@ -874,7 +815,6 @@ async def get_from_id(
874815 sandbox_id = sync_sandbox .sandbox_id ,
875816 app_id = sync_sandbox .app_id ,
876817 service_id = sync_sandbox .service_id ,
877- instance_id = sync_sandbox .instance_id ,
878818 name = sync_sandbox .name ,
879819 api_token = sync_sandbox .api_token ,
880820 sandbox_secret = sync_sandbox .sandbox_secret ,
@@ -952,7 +892,6 @@ async def create(
952892 sandbox_id = sync_result .sandbox_id ,
953893 app_id = sync_result .app_id ,
954894 service_id = sync_result .service_id ,
955- instance_id = sync_result .instance_id ,
956895 name = sync_result .name ,
957896 api_token = sync_result .api_token ,
958897 sandbox_secret = sync_result .sandbox_secret ,
@@ -1030,11 +969,6 @@ async def delete(self) -> None:
1030969 """Delete the sandbox instance asynchronously."""
1031970 pass
1032971
1033- @async_wrapper ("status" )
1034- async def status (self ) -> str :
1035- """Get current sandbox status asynchronously"""
1036- pass
1037-
1038972 @async_wrapper ("is_healthy" )
1039973 async def is_healthy (self ) -> bool :
1040974 """Check if sandbox is healthy and ready for operations asynchronously"""
0 commit comments