amo-server/scripts/start_services.py

181 lines
4.8 KiB
Python

#!/usr/bin/env python3
"""
Service startup script for AMO CRM service with FastStream workers.
This script starts Redis, FastAPI server, and FastStream workers in the
correct order for development.
"""
import subprocess
import sys
import time
import logging
import signal
import os
from typing import List
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Global list to track running processes
processes: List[subprocess.Popen] = []
def cleanup_processes() -> None:
"""Clean up all running processes."""
logger.info("Cleaning up processes...")
for process in processes:
if process.poll() is None: # Process is still running
logger.info(f"Terminating process {process.pid}")
process.terminate()
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
logger.warning(f"Force killing process {process.pid}")
process.kill()
def signal_handler(signum, frame) -> None:
"""Handle interrupt signals."""
logger.info("Received interrupt signal")
cleanup_processes()
sys.exit(0)
def start_redis() -> bool:
"""
Start Redis server.
Returns:
True if Redis is running, False otherwise
"""
try:
# Check if Redis is already running
result = subprocess.run(
["redis-cli", "ping"],
capture_output=True,
text=True,
timeout=5
)
if result.returncode == 0:
logger.info("Redis is already running")
return True
except (subprocess.TimeoutExpired, FileNotFoundError):
pass
logger.info("Starting Redis server...")
try:
process = subprocess.Popen(
["redis-server", "--daemonize", "yes"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
# Wait a moment for Redis to start
time.sleep(2)
# Check if Redis is now running
result = subprocess.run(
["redis-cli", "ping"],
capture_output=True,
text=True,
timeout=5
)
if result.returncode == 0:
logger.info("Redis started successfully")
return True
else:
logger.error("Failed to start Redis")
return False
except FileNotFoundError:
logger.error("Redis not found. Please install Redis first.")
logger.info("On Ubuntu/Debian: sudo apt install redis-server")
logger.info("On macOS: brew install redis")
logger.info("On Windows: Download from https://redis.io/download")
return False
def start_fastapi() -> subprocess.Popen:
"""
Start FastAPI server.
Returns:
Process object for the FastAPI server
"""
logger.info("Starting FastAPI server...")
process = subprocess.Popen([
"uv", "run", "uvicorn", "app:app",
"--host", "0.0.0.0",
"--port", "8000",
"--reload"
])
processes.append(process)
return process
def start_faststream_worker() -> subprocess.Popen:
"""
Start FastStream worker.
Returns:
Process object for the FastStream worker
"""
logger.info("Starting FastStream worker...")
process = subprocess.Popen([
"uv", "run", "faststream", "run", "workers.broker:app", "--reload"
])
processes.append(process)
return process
def main() -> None:
"""Main function to start all services."""
# Set up signal handlers
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
logger.info("Starting AMO CRM services...")
# Start Redis
if not start_redis():
logger.error("Failed to start Redis. Exiting.")
sys.exit(1)
# Start FastAPI server
fastapi_process = start_fastapi()
logger.info(f"FastAPI server started (PID: {fastapi_process.pid})")
# Wait a moment for FastAPI to start
time.sleep(3)
# Start FastStream worker
worker_process = start_faststream_worker()
logger.info(f"FastStream worker started (PID: {worker_process.pid})")
logger.info("All services started successfully!")
logger.info("FastAPI server: http://localhost:8000")
logger.info("API documentation: http://localhost:8000/docs")
logger.info("Press Ctrl+C to stop all services")
try:
# Wait for processes to complete
while True:
# Check if any process has died
for process in processes:
if process.poll() is not None:
logger.error(f"Process {process.pid} has died")
cleanup_processes()
sys.exit(1)
time.sleep(1)
except KeyboardInterrupt:
logger.info("Received interrupt, shutting down...")
cleanup_processes()
if __name__ == "__main__":
main()