prod deploy version

This commit is contained in:
OwusuBlessing
2025-06-11 17:40:17 +01:00
parent 3fcce3b464
commit 3bd6213a8d
6 changed files with 306 additions and 219 deletions
+6 -3
View File
@@ -410,10 +410,13 @@ async def generate_quiz_endpoint(
status_code=500, status_code=500,
detail=f"Unexpected error during quiz generation: {str(e)}" detail=f"Unexpected error during quiz generation: {str(e)}"
) )
@app.get("/health")
async def health_check():
"""Health check endpoint to verify the service is running."""
return {"status": "healthy", "timestamp": datetime.now().isoformat()}
@app.on_event("startup") @app.on_event("startup")
async def startup_event(): async def startup_event():
"""Initialize required components on startup""" """Initialize required components on startup"""
-216
View File
@@ -1,216 +0,0 @@
#!/bin/bash
# Configuration
SERVER_USER="your_username"
SERVER_IP="your_server_ip"
APP_DIR="/path/to/your/app"
PORT=5042
PYTHON_VERSION="3.11"
WORKERS=4
THREADS=2
TIMEOUT=120
MAX_REQUESTS=1000
MAX_REQUESTS_JITTER=50
DEBUG_MODE=false # Set to true for verbose output
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging function
log() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
case $level in
"INFO")
echo -e "${BLUE}[$timestamp] INFO: $message${NC}"
;;
"SUCCESS")
echo -e "${GREEN}[$timestamp] SUCCESS: $message${NC}"
;;
"WARNING")
echo -e "${YELLOW}[$timestamp] WARNING: $message${NC}"
;;
"ERROR")
echo -e "${RED}[$timestamp] ERROR: $message${NC}"
;;
esac
}
# Debug logging function
debug_log() {
if [ "$DEBUG_MODE" = true ]; then
echo -e "${YELLOW}[DEBUG] $1${NC}"
fi
}
# Error handling
set -e
trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
trap 'if [ $? -ne 0 ]; then log "ERROR" "Command failed: $last_command"; exit 1; fi' EXIT
log "INFO" "Starting deployment process..."
# Check if required packages are installed
log "INFO" "Checking required packages..."
if ! command -v ssh &> /dev/null; then
log "ERROR" "SSH is not installed. Please install it first."
exit 1
fi
# Create requirements.txt if it doesn't exist
if [ ! -f "requirements.txt" ]; then
log "INFO" "Creating requirements.txt..."
echo "fastapi==0.109.2
uvicorn==0.27.1
gunicorn==21.2.0
python-dotenv==1.0.1
langchain-openai==0.0.5
requests==2.31.0
PyPDF2==3.0.1" > requirements.txt
debug_log "Created requirements.txt with specific versions"
fi
# Create gunicorn config file
log "INFO" "Creating Gunicorn configuration..."
cat > gunicorn_config.py << EOL
import multiprocessing
import os
# Server socket
bind = "0.0.0.0:${PORT}"
backlog = 2048
# Worker processes
workers = ${WORKERS}
worker_class = "uvicorn.workers.UvicornWorker"
worker_connections = 1000
timeout = ${TIMEOUT}
keepalive = 2
# Process naming
proc_name = "firefighter"
pythonpath = "."
# Logging
accesslog = "logs/access.log"
errorlog = "logs/error.log"
loglevel = "info"
# Server mechanics
daemon = False
pidfile = "gunicorn.pid"
umask = 0
user = None
group = None
tmp_upload_dir = None
# SSL
keyfile = None
certfile = None
# Server hooks
def on_starting(server):
pass
def on_reload(server):
pass
def on_exit(server):
pass
# Worker lifecycle
max_requests = ${MAX_REQUESTS}
max_requests_jitter = ${MAX_REQUESTS_JITTER}
graceful_timeout = 30
preload_app = True
# Debug
reload = False
reload_engine = "auto"
spew = False
# Server mechanics
check_config = False
preload_app = True
EOL
debug_log "Created gunicorn_config.py with specified settings"
# Copy files to server
log "INFO" "Copying files to server..."
debug_log "Using SCP to copy files to $SERVER_USER@$SERVER_IP:$APP_DIR/"
scp -r ./* $SERVER_USER@$SERVER_IP:$APP_DIR/
# SSH into server and set up environment
log "INFO" "Setting up environment on server..."
ssh $SERVER_USER@$SERVER_IP << EOF
set -e
cd $APP_DIR
# Install Python 3.11 if not present
if ! command -v python${PYTHON_VERSION} &> /dev/null; then
echo "Installing Python ${PYTHON_VERSION}..."
sudo apt-get update
sudo apt-get install -y software-properties-common
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install -y python${PYTHON_VERSION} python${PYTHON_VERSION}-venv python${PYTHON_VERSION}-dev
fi
# Create virtual environment if it doesn't exist
if [ ! -d "venv" ]; then
python${PYTHON_VERSION} -m venv venv
fi
# Activate virtual environment and install dependencies
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
# Create systemd service file
sudo tee /etc/systemd/system/firefighter.service << 'EOL'
[Unit]
Description=Fire Fighter Interview API
After=network.target
[Service]
User=$SERVER_USER
WorkingDirectory=$APP_DIR
Environment="PATH=$APP_DIR/venv/bin"
Environment="PYTHONPATH=$APP_DIR"
ExecStart=$APP_DIR/venv/bin/gunicorn -c gunicorn_config.py app:app
Restart=always
RestartSec=5
StartLimitInterval=0
[Install]
WantedBy=multi-user.target
EOL
# Create log directory
mkdir -p logs
# Reload systemd and start service
sudo systemctl daemon-reload
sudo systemctl enable firefighter
sudo systemctl restart firefighter
# Check service status
sudo systemctl status firefighter
EOF
log "SUCCESS" "Deployment completed!"
log "INFO" "Your application should now be running at http://$SERVER_IP:$PORT"
log "INFO" "Check logs at $APP_DIR/logs/"
# Print helpful commands
echo -e "\n${BLUE}Useful commands:${NC}"
echo "View service status: sudo systemctl status firefighter"
echo "View logs: sudo journalctl -u firefighter -f"
echo "Restart service: sudo systemctl restart firefighter"
echo "Stop service: sudo systemctl stop firefighter"
+1
View File
@@ -0,0 +1 @@
18759
+77
View File
@@ -0,0 +1,77 @@
import multiprocessing
import os
# Server socket
bind = "0.0.0.0:5042" # Same port as in your app.py
backlog = 2048
# Worker processes
workers = multiprocessing.cpu_count() * 2 + 1 # Recommended formula for worker count
worker_class = "uvicorn.workers.UvicornWorker" # Required for FastAPI
worker_connections = 1000
timeout = 30
keepalive = 2
# Logging
accesslog = "logs/access.log"
errorlog = "logs/error.log"
loglevel = "info"
# Process naming
proc_name = "fire_fighter_api"
# SSL (uncomment and configure if using HTTPS)
# keyfile = "path/to/keyfile"
# certfile = "path/to/certfile"
# Server mechanics
daemon = False
pidfile = "gunicorn.pid"
umask = 0
user = None
group = None
tmp_upload_dir = None
# Server hooks
def on_starting(server):
"""
Server startup hook
"""
# Create logs directory if it doesn't exist
os.makedirs("logs", exist_ok=True)
def post_fork(server, worker):
"""
Worker initialization hook
"""
server.log.info("Worker spawned (pid: %s)", worker.pid)
def pre_fork(server, worker):
"""
Pre-fork hook
"""
pass
def pre_exec(server):
"""
Pre-exec hook
"""
server.log.info("Forked child, re-executing.")
def when_ready(server):
"""
Server ready hook
"""
server.log.info("Server is ready. Spawning workers")
def worker_int(worker):
"""
Worker interrupt hook
"""
worker.log.info("worker received INT or QUIT signal")
def worker_abort(worker):
"""
Worker abort hook
"""
worker.log.info("worker received SIGABRT signal")
+215
View File
@@ -0,0 +1,215 @@
#!/bin/bash
# Configuration
REPO_URL="http://owusu:890eccfcea010beb94a0adba246aaf9258330b70@23.29.118.76:3000/owusu/ds-fire-fighter.git"
APP_DIR="/home/owusu/ds-fire-fighter"
BRANCH="main"
PYTHON_VERSION="3.11"
WORKERS=4
THREADS=2
TIMEOUT=120
MAX_REQUESTS=1000
MAX_REQUESTS_JITTER=50
DEBUG_MODE=true
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging function
log() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
case $level in
"INFO")
echo -e "${BLUE}[$timestamp] INFO: $message${NC}"
;;
"SUCCESS")
echo -e "${GREEN}[$timestamp] SUCCESS: $message${NC}"
;;
"WARNING")
echo -e "${YELLOW}[$timestamp] WARNING: $message${NC}"
;;
"ERROR")
echo -e "${RED}[$timestamp] ERROR: $message${NC}"
;;
esac
}
# Debug logging function
debug_log() {
if [ "$DEBUG_MODE" = true ]; then
echo -e "${YELLOW}[DEBUG] $1${NC}"
fi
}
# Error handling
set -e
trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
trap 'if [ $? -ne 0 ]; then log "ERROR" "Command failed: $last_command"; exit 1; fi' EXIT
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Function to install Python 3.11
install_python() {
log "INFO" "Installing Python ${PYTHON_VERSION}..."
sudo apt-get update
sudo apt-get install -y software-properties-common
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install -y python${PYTHON_VERSION} python${PYTHON_VERSION}-venv python${PYTHON_VERSION}-dev
}
# Function to setup git repository
setup_repo() {
if [ ! -d "$APP_DIR" ]; then
log "INFO" "Cloning repository..."
git clone $REPO_URL $APP_DIR
else
log "INFO" "Updating repository..."
cd $APP_DIR
git fetch origin
git reset --hard origin/$BRANCH
git clean -fd
fi
}
# Function to setup virtual environment
setup_venv() {
log "INFO" "Setting up virtual environment..."
if [ ! -d "$APP_DIR/venv" ]; then
python${PYTHON_VERSION} -m venv $APP_DIR/venv
fi
source $APP_DIR/venv/bin/activate
pip install --upgrade pip
pip install -r $APP_DIR/requirements.txt
}
# Function to create gunicorn config
create_gunicorn_config() {
log "INFO" "Creating Gunicorn configuration..."
cat > $APP_DIR/gunicorn_config.py << EOL
import multiprocessing
import os
# Server socket
bind = "0.0.0.0:5042"
backlog = 2048
# Worker processes
workers = ${WORKERS}
worker_class = "uvicorn.workers.UvicornWorker"
worker_connections = 1000
timeout = ${TIMEOUT}
keepalive = 2
# Process naming
proc_name = "firefighter"
pythonpath = "."
# Logging
accesslog = "logs/access.log"
errorlog = "logs/error.log"
loglevel = "info"
# Server mechanics
daemon = False
pidfile = "gunicorn.pid"
umask = 0
user = None
group = None
tmp_upload_dir = None
# Worker lifecycle
max_requests = ${MAX_REQUESTS}
max_requests_jitter = ${MAX_REQUESTS_JITTER}
graceful_timeout = 30
preload_app = True
# Debug
reload = False
reload_engine = "auto"
spew = False
# Server mechanics
check_config = False
preload_app = True
EOL
}
# Function to setup systemd service
setup_service() {
log "INFO" "Setting up systemd service..."
sudo tee /etc/systemd/system/firefighter.service << EOL
[Unit]
Description=Fire Fighter Interview API
After=network.target
[Service]
User=$USER
WorkingDirectory=$APP_DIR
Environment="PATH=$APP_DIR/venv/bin"
Environment="PYTHONPATH=$APP_DIR"
ExecStart=$APP_DIR/start.sh
Restart=always
RestartSec=5
StartLimitInterval=0
[Install]
WantedBy=multi-user.target
EOL
sudo systemctl daemon-reload
sudo systemctl enable firefighter
}
# Main deployment process
main() {
log "INFO" "Starting deployment process..."
# Check and install Python if needed
if ! command_exists python${PYTHON_VERSION}; then
install_python
fi
# Setup repository
setup_repo
# Create logs directory
mkdir -p $APP_DIR/logs
# Setup virtual environment and install dependencies
setup_venv
# Create gunicorn config
create_gunicorn_config
# Setup and start service
setup_service
sudo systemctl restart firefighter
log "SUCCESS" "Deployment completed!"
log "INFO" "Your application should now be running at http://localhost:5042"
# Print helpful commands
echo -e "\n${BLUE}Useful commands:${NC}"
echo "View service status: sudo systemctl status firefighter"
echo "View logs: sudo journalctl -u firefighter -f"
echo "View application logs: tail -f $APP_DIR/logs/access.log"
echo "View error logs: tail -f $APP_DIR/logs/error.log"
echo "Restart service: sudo systemctl restart firefighter"
echo "Stop service: sudo systemctl stop firefighter"
echo "Start service: sudo systemctl start firefighter"
echo "Deploy new version: ./server_deploy.sh"
}
# Run main function
main
Executable
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
# Create logs directory if it doesn't exist
mkdir -p logs
# Start Gunicorn with the configuration
gunicorn -c gunicorn_config.py app:app