Add CLI stop server command (#2775)
This commit is contained in:
committed by
GitHub
parent
41f77a40c8
commit
7ecee11d93
@@ -6,6 +6,7 @@ from .init_command import init, init_browser
|
|||||||
from .quickstart import quickstart_app
|
from .quickstart import quickstart_app
|
||||||
from .run_commands import run_app
|
from .run_commands import run_app
|
||||||
from .status import status_app
|
from .status import status_app
|
||||||
|
from .stop_commands import stop_app
|
||||||
from .tasks import tasks_app
|
from .tasks import tasks_app
|
||||||
from .workflow import workflow_app
|
from .workflow import workflow_app
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ cli_app.add_typer(workflow_app, name="workflow", help="Workflow management comma
|
|||||||
cli_app.add_typer(tasks_app, name="tasks", help="Task management commands.")
|
cli_app.add_typer(tasks_app, name="tasks", help="Task management commands.")
|
||||||
cli_app.add_typer(docs_app, name="docs", help="Open Skyvern documentation.")
|
cli_app.add_typer(docs_app, name="docs", help="Open Skyvern documentation.")
|
||||||
cli_app.add_typer(status_app, name="status", help="Check if Skyvern services are running.")
|
cli_app.add_typer(status_app, name="status", help="Check if Skyvern services are running.")
|
||||||
|
cli_app.add_typer(stop_app, name="stop", help="Stop Skyvern services.")
|
||||||
init_app = typer.Typer(
|
init_app = typer.Typer(
|
||||||
invoke_without_command=True,
|
invoke_without_command=True,
|
||||||
help="Interactively configure Skyvern and its dependencies.",
|
help="Interactively configure Skyvern and its dependencies.",
|
||||||
|
|||||||
75
skyvern/cli/stop_commands.py
Normal file
75
skyvern/cli/stop_commands.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
|
import psutil
|
||||||
|
import typer
|
||||||
|
from rich.panel import Panel
|
||||||
|
|
||||||
|
from .console import console
|
||||||
|
|
||||||
|
stop_app = typer.Typer(help="Commands to stop Skyvern services.")
|
||||||
|
|
||||||
|
|
||||||
|
def get_pids_on_port(port: int) -> List[int]:
|
||||||
|
"""Return a list of PIDs listening on the given port."""
|
||||||
|
pids = []
|
||||||
|
try:
|
||||||
|
for conn in psutil.net_connections(kind="inet"):
|
||||||
|
if conn.laddr and conn.laddr.port == port and conn.pid and conn.status == psutil.CONN_LISTEN:
|
||||||
|
pids.append(conn.pid)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return list(set(pids))
|
||||||
|
|
||||||
|
|
||||||
|
def kill_pids(pids: List[int], service_name: str) -> bool:
|
||||||
|
"""Kill the given list of PIDs in a cross-platform way."""
|
||||||
|
if not pids:
|
||||||
|
console.print(f"[yellow]No {service_name} processes found.[/yellow]")
|
||||||
|
return False
|
||||||
|
|
||||||
|
killed_any = False
|
||||||
|
for pid in pids:
|
||||||
|
try:
|
||||||
|
# Use psutil for cross-platform process killing
|
||||||
|
process = psutil.Process(pid)
|
||||||
|
process.terminate()
|
||||||
|
|
||||||
|
# Wait for the process to exit, use kill() as fallback
|
||||||
|
process_stopped = False
|
||||||
|
try:
|
||||||
|
process.wait(timeout=3)
|
||||||
|
process_stopped = True
|
||||||
|
except psutil.TimeoutExpired:
|
||||||
|
console.print(f"[yellow]Process {pid} didn't terminate gracefully, forcing kill...[/yellow]")
|
||||||
|
process.kill()
|
||||||
|
try:
|
||||||
|
process.wait(timeout=3)
|
||||||
|
process_stopped = True
|
||||||
|
except psutil.TimeoutExpired:
|
||||||
|
console.print(f"[red]Process {pid} remains unresponsive even after force kill[/red]")
|
||||||
|
|
||||||
|
if process_stopped:
|
||||||
|
killed_any = True
|
||||||
|
console.print(f"[green]✅ Stopped {service_name} process (PID: {pid})[/green]")
|
||||||
|
else:
|
||||||
|
console.print(f"[red]❌ Failed to stop {service_name} process (PID: {pid})[/red]")
|
||||||
|
except psutil.NoSuchProcess:
|
||||||
|
console.print(f"[yellow]Process {pid} was already stopped[/yellow]")
|
||||||
|
except psutil.AccessDenied:
|
||||||
|
console.print(f"[red]Access denied when trying to stop process {pid}[/red]")
|
||||||
|
except Exception as e:
|
||||||
|
console.print(f"[red]Failed to stop process {pid}: {e}[/red]")
|
||||||
|
|
||||||
|
return killed_any
|
||||||
|
|
||||||
|
|
||||||
|
@stop_app.command(name="server")
|
||||||
|
def stop_server(port: int = typer.Option(8000, "--port", "-p", help="Port number for the Skyvern API server")) -> None:
|
||||||
|
"""Stop the Skyvern API server running on the specified port (default: 8000)."""
|
||||||
|
console.print(Panel(f"[bold red]Stopping Skyvern API Server (port {port})...[/bold red]", border_style="red"))
|
||||||
|
|
||||||
|
pids = get_pids_on_port(port)
|
||||||
|
if kill_pids(pids, f"Skyvern API server (port {port})"):
|
||||||
|
console.print(f"[green]🛑 Skyvern API server on port {port} stopped successfully.[/green]")
|
||||||
|
else:
|
||||||
|
console.print(f"[yellow]No Skyvern API server found running on port {port}.[/yellow]")
|
||||||
Reference in New Issue
Block a user