181 lines
4.8 KiB
Python
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()
|