124 lines
3.3 KiB
Python
124 lines
3.3 KiB
Python
"""
|
|
pyserve down - Stop all services
|
|
"""
|
|
|
|
import signal
|
|
import time
|
|
from pathlib import Path
|
|
from typing import Any, cast
|
|
|
|
import click
|
|
|
|
|
|
@click.command("down")
|
|
@click.option(
|
|
"--timeout",
|
|
"timeout",
|
|
default=30,
|
|
type=int,
|
|
help="Timeout in seconds for graceful shutdown",
|
|
)
|
|
@click.option(
|
|
"-v",
|
|
"--volumes",
|
|
is_flag=True,
|
|
help="Remove volumes/data",
|
|
)
|
|
@click.option(
|
|
"--remove-orphans",
|
|
is_flag=True,
|
|
help="Remove orphaned services",
|
|
)
|
|
@click.pass_obj
|
|
def down_cmd(
|
|
ctx: Any,
|
|
timeout: int,
|
|
volumes: bool,
|
|
remove_orphans: bool,
|
|
) -> None:
|
|
"""
|
|
Stop and remove all services.
|
|
|
|
\b
|
|
Examples:
|
|
pyserve down # Stop all services
|
|
pyserve down --timeout 60 # Extended shutdown timeout
|
|
pyserve down -v # Remove volumes too
|
|
"""
|
|
from ..output import console, print_error, print_info, print_success, print_warning
|
|
from ..state import StateManager
|
|
|
|
state_manager = StateManager(Path(".pyserve"), ctx.project)
|
|
|
|
if state_manager.is_daemon_running():
|
|
daemon_pid = state_manager.get_daemon_pid()
|
|
console.print(f"[bold]Stopping PyServe daemon (PID: {daemon_pid})...[/bold]")
|
|
|
|
try:
|
|
import os
|
|
|
|
# FIXME: Please fix the cast usage here
|
|
os.kill(cast(int, daemon_pid), signal.SIGTERM)
|
|
|
|
start_time = time.time()
|
|
while time.time() - start_time < timeout:
|
|
try:
|
|
# FIXME: Please fix the cast usage here
|
|
os.kill(cast(int, daemon_pid), 0)
|
|
time.sleep(0.5)
|
|
except ProcessLookupError:
|
|
break
|
|
else:
|
|
print_warning("Graceful shutdown timed out, forcing...")
|
|
try:
|
|
# FIXME: Please fix the cast usage here
|
|
os.kill(cast(int, daemon_pid), signal.SIGKILL)
|
|
except ProcessLookupError:
|
|
pass
|
|
|
|
state_manager.clear_daemon_pid()
|
|
print_success("PyServe daemon stopped")
|
|
|
|
except ProcessLookupError:
|
|
print_info("Daemon was not running")
|
|
state_manager.clear_daemon_pid()
|
|
except PermissionError:
|
|
print_error("Permission denied to stop daemon")
|
|
raise click.Abort()
|
|
else:
|
|
services = state_manager.get_all_services()
|
|
|
|
if not services:
|
|
print_info("No services are running")
|
|
return
|
|
|
|
console.print("[bold]Stopping services...[/bold]")
|
|
|
|
from ...config import Config
|
|
from .._runner import ServiceRunner
|
|
|
|
config_path = Path(ctx.config_file)
|
|
if config_path.exists():
|
|
config = Config.from_yaml(str(config_path))
|
|
else:
|
|
config = Config()
|
|
|
|
runner = ServiceRunner(config, state_manager)
|
|
|
|
import asyncio
|
|
|
|
try:
|
|
asyncio.run(runner.stop_all(timeout=timeout))
|
|
print_success("All services stopped")
|
|
except Exception as e:
|
|
print_error(f"Error stopping services: {e}")
|
|
|
|
if volumes:
|
|
console.print("Cleaning up state...")
|
|
state_manager.clear()
|
|
print_info("State cleared")
|
|
|
|
if remove_orphans:
|
|
# This would remove services that are in state but not in config
|
|
pass
|