""" pyserve start/stop/restart - Service management commands """ import asyncio from pathlib import Path from typing import Any, Dict import click @click.command("start") @click.argument("services", nargs=-1, required=True) @click.option( "--timeout", "timeout", default=60, type=int, help="Timeout in seconds for service startup", ) @click.pass_obj def start_cmd(ctx: Any, services: tuple[str, ...], timeout: int) -> None: """ Start one or more services. \b Examples: pyserve start api # Start api service pyserve start api admin # Start multiple services """ from ...config import Config from .._runner import ServiceRunner from ..output import console, print_error, print_success from ..state import StateManager config_path = Path(ctx.config_file) if not config_path.exists(): print_error(f"Configuration file not found: {config_path}") raise click.Abort() config = Config.from_yaml(str(config_path)) state_manager = StateManager(Path(".pyserve"), ctx.project) runner = ServiceRunner(config, state_manager) console.print(f"[bold]Starting services: {', '.join(services)}[/bold]") async def do_start() -> Dict[str, bool]: results: Dict[str, bool] = {} for service in services: try: success = await runner.start_service(service, timeout=timeout) results[service] = success if success: print_success(f"Started {service}") else: print_error(f"Failed to start {service}") except Exception as e: print_error(f"Error starting {service}: {e}") results[service] = False return results try: results = asyncio.run(do_start()) if not all(results.values()): raise click.Abort() except Exception as e: print_error(f"Error: {e}") raise click.Abort() @click.command("stop") @click.argument("services", nargs=-1, required=True) @click.option( "--timeout", "timeout", default=30, type=int, help="Timeout in seconds for graceful shutdown", ) @click.option( "-f", "--force", is_flag=True, help="Force stop (SIGKILL)", ) @click.pass_obj def stop_cmd(ctx: Any, services: tuple[str, ...], timeout: int, force: bool) -> None: """ Stop one or more services. \b Examples: pyserve stop api # Stop api service pyserve stop api admin # Stop multiple services pyserve stop api --force # Force stop """ from ...config import Config from .._runner import ServiceRunner from ..output import console, print_error, print_success from ..state import StateManager config_path = Path(ctx.config_file) config = Config.from_yaml(str(config_path)) if config_path.exists() else Config() state_manager = StateManager(Path(".pyserve"), ctx.project) runner = ServiceRunner(config, state_manager) console.print(f"[bold]Stopping services: {', '.join(services)}[/bold]") async def do_stop() -> Dict[str, bool]: results: Dict[str, bool] = {} for service in services: try: success = await runner.stop_service(service, timeout=timeout, force=force) results[service] = success if success: print_success(f"Stopped {service}") else: print_error(f"Failed to stop {service}") except Exception as e: print_error(f"Error stopping {service}: {e}") results[service] = False return results try: results = asyncio.run(do_stop()) if not all(results.values()): raise click.Abort() except Exception as e: print_error(f"Error: {e}") raise click.Abort() @click.command("restart") @click.argument("services", nargs=-1, required=True) @click.option( "--timeout", "timeout", default=60, type=int, help="Timeout in seconds for restart", ) @click.pass_obj def restart_cmd(ctx: Any, services: tuple[str, ...], timeout: int) -> None: """ Restart one or more services. \b Examples: pyserve restart api # Restart api service pyserve restart api admin # Restart multiple services """ from ...config import Config from .._runner import ServiceRunner from ..output import console, print_error, print_success from ..state import StateManager config_path = Path(ctx.config_file) if not config_path.exists(): print_error(f"Configuration file not found: {config_path}") raise click.Abort() config = Config.from_yaml(str(config_path)) state_manager = StateManager(Path(".pyserve"), ctx.project) runner = ServiceRunner(config, state_manager) console.print(f"[bold]Restarting services: {', '.join(services)}[/bold]") async def do_restart() -> Dict[str, bool]: results = {} for service in services: try: success = await runner.restart_service(service, timeout=timeout) results[service] = success if success: print_success(f"Restarted {service}") else: print_error(f"Failed to restart {service}") except Exception as e: print_error(f"Error restarting {service}: {e}") results[service] = False return results try: results = asyncio.run(do_restart()) if not all(results.values()): raise click.Abort() except Exception as e: print_error(f"Error: {e}") raise click.Abort()