66from pathlib import Path
77from typing import Optional
88
9- import ray
109import typer
1110from rich .console import Console
1211from rich .logging import RichHandler
1615from ..core .config import StudyConfig
1716from ..core .storage .postgres_utils import clear_study_data , verify_database_connection
1817from ..core .study_controller import StudyController
19- from ..execution .backends import RayExecutionBackend
18+ from ..execution .backends import LocalExecutionBackend , RayExecutionBackend
2019from ..logging .manager import CentralizedLogger , LogStreamer
2120
2221# Setup rich console and app
@@ -116,7 +115,7 @@ def optimize_command(
116115 "ray" ,
117116 "--backend" ,
118117 "-b" ,
119- help = "Execution backend: 'ray' (only supported option )" ,
118+ help = "Execution backend: 'ray' or 'local' (single worker, no Ray )" ,
120119 ),
121120 n_trials : Optional [int ] = typer .Option (
122121 None , "--trials" , "-n" , help = "Number of trials (overrides config)"
@@ -150,27 +149,32 @@ def optimize_command(
150149 """Run optimization study."""
151150 setup_logging (verbose )
152151
153- # Validate Python environment options (exactly one should be specified )
152+ # Validate Python environment options for Ray backend (exactly one required )
154153 python_env_options = [python_executable , venv_path , conda_env ]
155154 specified_options = [opt for opt in python_env_options if opt is not None ]
156155
157- if len (specified_options ) == 0 :
158- console .print (
159- "[bold red]"
160- "Error: At least one Python environment option must be specified"
161- "[/bold red]"
162- )
163- console .print ("Choose one of: --python-executable, --venv-path, or --conda-env" )
164- raise typer .Exit (1 )
165-
166- if len (specified_options ) > 1 :
167- console .print (
168- "[bold red]"
169- "Error: Only one Python environment option can be specified at a time"
170- "[/bold red]"
171- )
172- console .print ("Choose one of: --python-executable, --venv-path, or --conda-env" )
173- raise typer .Exit (1 )
156+ if backend .lower () == "ray" :
157+ if len (specified_options ) == 0 :
158+ console .print (
159+ "[bold red]"
160+ "Error: At least one Python environment option must be specified "
161+ "for Ray backend"
162+ "[/bold red]"
163+ )
164+ console .print (
165+ "Choose one of: --python-executable, --venv-path, or --conda-env"
166+ )
167+ raise typer .Exit (1 )
168+ if len (specified_options ) > 1 :
169+ console .print (
170+ "[bold red]"
171+ "Error: Only one Python environment option can be specified at a time"
172+ "[/bold red]"
173+ )
174+ console .print (
175+ "Choose one of: --python-executable, --venv-path, or --conda-env"
176+ )
177+ raise typer .Exit (1 )
174178
175179 console .print ("[bold green]Starting auto-tune-vllm optimization[/bold green]" )
176180 console .print (f"Configuration: { config } " )
@@ -188,6 +192,9 @@ def optimize_command(
188192 "[yellow]No Python environment specified, using auto-detection[/yellow]"
189193 )
190194
195+ if backend .lower () == "local" :
196+ console .print ("[blue]Using local execution (single worker, no Ray)[/blue]" )
197+
191198 try :
192199 # Load configuration
193200 config_path = Path (config )
@@ -222,40 +229,35 @@ def optimize_command(
222229 "Ray auto-start disabled - requires existing cluster"
223230 "[/yellow]"
224231 )
225- else :
226- console .print (
227- "[bold red]"
228- "Error: Local execution backend is not supported in this version."
229- "[/bold red]"
230- )
231- console .print (
232- "[bold red]Only Ray distributed execution is available.[/bold red]"
233- )
234- console .print (
235- "[blue]Use --backend ray (default) or set up a Ray cluster.[/blue]"
236- )
237- console .print (
238- "[blue]See docs/ray_cluster_setup.md for Ray setup instructions.[/blue]"
232+ elif backend .lower () == "local" :
233+ max_local = (
234+ max_concurrent_trials
235+ or study_config .optimization .max_concurrent_trials
236+ or 1
239237 )
238+ execution_backend = LocalExecutionBackend (max_concurrent = max_local )
239+ else :
240+ console .print (f"[bold red]Error: Unknown backend '{ backend } '.[/bold red]" )
241+ console .print ("[blue]Use --backend ray or --backend local.[/blue]" )
240242 raise typer .Exit (1 )
241243
242244 # Run optimization
243- # Use CLI value or fall back to YAML config
245+ # Use CLI value or fall back to YAML config (default 1 for local backend)
244246 final_max_concurrent_trials = (
245247 max_concurrent_trials or study_config .optimization .max_concurrent_trials
246248 )
247249 if final_max_concurrent_trials is None :
248- console . print (
249- "[bold red]"
250- "❌ --max-concurrent-trials is required "
251- "(or set optimization.max_concurrent_trials in the config)"
252- "[/ bold red]"
253- )
254- console . print (
255- "YAML: \n optimization: \n "
256- " max_concurrent_trials: 2"
257- )
258- raise typer .Exit (1 )
250+ if backend . lower () == "local" :
251+ final_max_concurrent_trials = 1
252+ else :
253+ console . print (
254+ "[ bold red]"
255+ "❌ --max-concurrent-trials is required "
256+ "(or set optimization.max_concurrent_trials in the config)"
257+ "[/bold red] "
258+ )
259+ console . print ( "YAML: \n optimization: \n max_concurrent_trials: 2" )
260+ raise typer .Exit (1 )
259261 if final_max_concurrent_trials < 1 :
260262 console .print (
261263 "[bold red]❌ --max-concurrent-trials must be >= 1[/bold red]"
@@ -405,8 +407,7 @@ def run_optimization_sync(
405407 # User interrupted with Ctrl+C
406408 progress .update (task , description = "⚠️ Optimization interrupted by user" )
407409 logger .warning (
408- "Keyboard interrupt received (Ctrl+C). "
409- "Initiating graceful shutdown..."
410+ "Keyboard interrupt received (Ctrl+C). Initiating graceful shutdown..."
410411 )
411412 console .print (
412413 "\n [yellow]⚠️ Interrupt signal received. "
@@ -815,7 +816,7 @@ def resume_command(
815816 "ray" ,
816817 "--backend" ,
817818 "-b" ,
818- help = "Execution backend: 'ray' (only supported option )" ,
819+ help = "Execution backend: 'ray' or 'local' (single worker, no Ray )" ,
819820 ),
820821 n_trials : Optional [int ] = typer .Option (
821822 None , "--trials" , "-n" , help = "Number of additional trials to run"
@@ -851,27 +852,32 @@ def resume_command(
851852 """Resume an existing optimization study. Fails if the study doesn't exist."""
852853 setup_logging (verbose )
853854
854- # Validate Python environment options (exactly one should be specified )
855+ # Validate Python environment options for Ray backend (exactly one required )
855856 python_env_options = [python_executable , venv_path , conda_env ]
856857 specified_options = [opt for opt in python_env_options if opt is not None ]
857858
858- if len (specified_options ) == 0 :
859- console .print (
860- "[bold red]"
861- "Error: At least one Python environment option must be specified"
862- "[/bold red]"
863- )
864- console .print ("Choose one of: --python-executable, --venv-path, or --conda-env" )
865- raise typer .Exit (1 )
866-
867- if len (specified_options ) > 1 :
868- console .print (
869- "[bold red]"
870- "Error: Only one Python environment option can be specified at a time"
871- "[/bold red]"
872- )
873- console .print ("Choose one of: --python-executable, --venv-path, or --conda-env" )
874- raise typer .Exit (1 )
859+ if backend .lower () == "ray" :
860+ if len (specified_options ) == 0 :
861+ console .print (
862+ "[bold red]"
863+ "Error: At least one Python environment option must be specified "
864+ "for Ray backend"
865+ "[/bold red]"
866+ )
867+ console .print (
868+ "Choose one of: --python-executable, --venv-path, or --conda-env"
869+ )
870+ raise typer .Exit (1 )
871+ if len (specified_options ) > 1 :
872+ console .print (
873+ "[bold red]"
874+ "Error: Only one Python environment option can be specified at a time"
875+ "[/bold red]"
876+ )
877+ console .print (
878+ "Choose one of: --python-executable, --venv-path, or --conda-env"
879+ )
880+ raise typer .Exit (1 )
875881
876882 console .print ("[bold blue]Resuming auto-tune-vllm study[/bold blue]" )
877883
@@ -900,49 +906,45 @@ def resume_command(
900906 "Ray auto-start disabled - requires existing cluster"
901907 "[/yellow]"
902908 )
903-
904- else :
905- console .print (
906- "[bold red]"
907- "Error: Local execution backend is not supported in this version."
908- "[/bold red]"
909- )
910- console .print (
911- "[bold red]Only Ray distributed execution is available.[/bold red]"
912- )
913- console .print (
914- "[blue]Use --backend ray (default) or set up a Ray cluster.[/blue]"
915- )
916- console .print (
917- "[blue]See docs/ray_cluster_setup.md for Ray setup instructions.[/blue]"
909+ elif backend .lower () == "local" :
910+ max_local = (
911+ max_concurrent_trials
912+ or study_config .optimization .max_concurrent_trials
913+ or 1
918914 )
915+ execution_backend = LocalExecutionBackend (max_concurrent = max_local )
916+ else :
917+ console .print (f"[bold red]Error: Unknown backend '{ backend } '.[/bold red]" )
918+ console .print ("[blue]Use --backend ray or --backend local.[/blue]" )
919919 raise typer .Exit (1 )
920920
921921 # Resume study
922- # Use CLI value or fall back to YAML config
922+ # Use CLI value or fall back to YAML config (default 1 for local backend)
923923 final_max_concurrent_trials = (
924924 max_concurrent_trials or study_config .optimization .max_concurrent_trials
925925 )
926926 if n_trials or n_total_trials : # Only required if we will run new trials
927927 if final_max_concurrent_trials is None :
928- console .print (
929- "[bold red]"
930- "❌ --max-concurrent-trials is required to resume "
931- "with new trials"
932- "[/bold red]"
933- )
934- console .print (
935- "Set CLI flag or config: "
936- "optimization.max_concurrent_trials"
937- )
938- raise typer .Exit (1 )
928+ if backend .lower () == "local" :
929+ final_max_concurrent_trials = 1
930+ else :
931+ console .print (
932+ "[bold red]"
933+ "❌ --max-concurrent-trials is required to resume "
934+ "with new trials"
935+ "[/bold red]"
936+ )
937+ console .print (
938+ "Set CLI flag or config: optimization.max_concurrent_trials"
939+ )
940+ raise typer .Exit (1 )
939941 if final_max_concurrent_trials < 1 :
940942 console .print (
941- "[bold red]"
942- "❌ --max-concurrent-trials must be >= 1"
943- "[/bold red]"
943+ "[bold red]❌ --max-concurrent-trials must be >= 1[/bold red]"
944944 )
945945 raise typer .Exit (1 )
946+ if final_max_concurrent_trials is None and backend .lower () == "local" :
947+ final_max_concurrent_trials = 1
946948 resume_study_sync (
947949 execution_backend ,
948950 study_config ,
@@ -1245,6 +1247,7 @@ def check_environment_command(
12451247def _check_ray_cluster_environment ():
12461248 """Check environment on all Ray cluster nodes."""
12471249 try :
1250+ import ray
12481251
12491252 if not ray .is_initialized ():
12501253 console .print ("[yellow]Initializing Ray connection...[/yellow]" )
0 commit comments