2424 BaseExecutor ,
2525 EntryKind ,
2626 ExecutionResult ,
27+ HealthCheck ,
2728 StreamChunk ,
2829 StreamEvent ,
2930 StreamResult ,
@@ -49,6 +50,51 @@ def __init__(self) -> None:
4950 self .image = PYTHON_EXECUTOR_DOCKER_IMAGE
5051 self .run_args = PYTHON_EXECUTOR_DOCKER_RUN_ARGS
5152
53+ def check_health (self ) -> HealthCheck :
54+ """Verify Docker daemon is reachable and the executor image is available."""
55+ # Check Docker daemon connectivity
56+ try :
57+ result = subprocess .run (
58+ [self .docker_binary , "version" , "--format" , "{{.Server.Version}}" ],
59+ capture_output = True ,
60+ timeout = 5 ,
61+ check = False ,
62+ )
63+ except FileNotFoundError :
64+ return HealthCheck (status = "error" , message = "Docker binary not found" )
65+ except subprocess .TimeoutExpired :
66+ return HealthCheck (status = "error" , message = "Docker daemon not responding" )
67+
68+ if result .returncode != 0 :
69+ stderr = result .stderr .decode ("utf-8" , errors = "replace" ).strip ()
70+ return HealthCheck (
71+ status = "error" ,
72+ message = f"Docker daemon not reachable: { stderr } " ,
73+ )
74+
75+ # Check executor image is available locally
76+ image_with_tag = f"{ self .image } :latest"
77+ try :
78+ img_result = subprocess .run (
79+ [self .docker_binary , "image" , "inspect" , image_with_tag ],
80+ capture_output = True ,
81+ timeout = 5 ,
82+ check = False ,
83+ )
84+ except subprocess .TimeoutExpired :
85+ return HealthCheck (
86+ status = "error" ,
87+ message = f"Timeout checking image { image_with_tag } " ,
88+ )
89+
90+ if img_result .returncode != 0 :
91+ return HealthCheck (
92+ status = "error" ,
93+ message = f"Executor image { image_with_tag } not available locally" ,
94+ )
95+
96+ return HealthCheck (status = "ok" )
97+
5298 def _resolve_docker_binary (self ) -> str :
5399 candidate = PYTHON_EXECUTOR_DOCKER_BIN
54100 docker_path = which (candidate )
0 commit comments