126 lines
3.5 KiB
Python
126 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Startup script for the Alpine Bits Python Server API.
|
|
|
|
This script:
|
|
1. Runs database migrations using Alembic
|
|
2. Starts the FastAPI application with uvicorn
|
|
|
|
Database migrations are run BEFORE starting the server to ensure the schema
|
|
is up to date. This approach works well with multiple workers since migrations
|
|
complete before any worker starts processing requests.
|
|
"""
|
|
|
|
import argparse
|
|
import sys
|
|
|
|
import uvicorn
|
|
|
|
from alpine_bits_python.run_migrations import run_migrations
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
"""Parse command line arguments for uvicorn configuration."""
|
|
parser = argparse.ArgumentParser(
|
|
description="Run Alpine Bits Python Server with database migrations"
|
|
)
|
|
parser.add_argument(
|
|
"--host",
|
|
type=str,
|
|
default="0.0.0.0",
|
|
help="Host to bind to (default: 0.0.0.0)",
|
|
)
|
|
parser.add_argument(
|
|
"--port",
|
|
type=int,
|
|
default=8080,
|
|
help="Port to bind to (default: 8080)",
|
|
)
|
|
parser.add_argument(
|
|
"--workers",
|
|
type=int,
|
|
default=1,
|
|
help="Number of worker processes (default: 1)",
|
|
)
|
|
parser.add_argument(
|
|
"--reload",
|
|
action="store_true",
|
|
default=False,
|
|
help="Enable auto-reload for development (default: False)",
|
|
)
|
|
parser.add_argument(
|
|
"--log-level",
|
|
type=str,
|
|
default="info",
|
|
choices=["critical", "error", "warning", "info", "debug", "trace"],
|
|
help="Log level (default: info)",
|
|
)
|
|
parser.add_argument(
|
|
"--access-log",
|
|
action="store_true",
|
|
default=False,
|
|
help="Enable access log (default: False)",
|
|
)
|
|
parser.add_argument(
|
|
"--forwarded-allow-ips",
|
|
type=str,
|
|
default="127.0.0.1",
|
|
help=(
|
|
"Comma-separated list of IPs to trust for proxy headers "
|
|
"(default: 127.0.0.1)"
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--proxy-headers",
|
|
action="store_true",
|
|
default=False,
|
|
help="Enable proxy headers (X-Forwarded-* headers) (default: False)",
|
|
)
|
|
parser.add_argument(
|
|
"--no-server-header",
|
|
action="store_true",
|
|
default=False,
|
|
help="Disable Server header in responses (default: False)",
|
|
)
|
|
parser.add_argument(
|
|
"--timeout-graceful-shutdown",
|
|
type=int,
|
|
default=300,
|
|
help=(
|
|
"Graceful shutdown timeout in seconds. Workers have this long to finish "
|
|
"background tasks before being killed (default: 300)"
|
|
),
|
|
)
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Parse command line arguments
|
|
args = parse_args()
|
|
|
|
# Run database migrations before starting the server
|
|
# This ensures the schema is up to date before any workers start
|
|
print("Running database migrations...")
|
|
try:
|
|
run_migrations()
|
|
print("Database migrations completed successfully")
|
|
except Exception as e:
|
|
print(f"Failed to run migrations: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Start the API server
|
|
print("Starting API server...")
|
|
uvicorn.run(
|
|
"alpine_bits_python.api:app",
|
|
host=args.host,
|
|
port=args.port,
|
|
workers=args.workers,
|
|
reload=args.reload,
|
|
log_level=args.log_level,
|
|
access_log=args.access_log,
|
|
forwarded_allow_ips=args.forwarded_allow_ips,
|
|
proxy_headers=args.proxy_headers,
|
|
server_header=not args.no_server_header,
|
|
timeout_graceful_shutdown=args.timeout_graceful_shutdown,
|
|
)
|