← Back to all snippets
BASH

Graceful Service Restart with PID File and Health Check

Implement a robust Bash script to gracefully stop, start, and restart a service using a PID file, including a basic HTTP health check for reliability in deployments.

#!/bin/bash

SERVICE_NAME="my_web_service"
PID_FILE="/var/run/$SERVICE_NAME.pid"
LOG_FILE="/var/log/$SERVICE_NAME.log"
START_CMD="node /path/to/your/app.js > $LOG_FILE 2>&1 & echo \$! > $PID_FILE" # Example: Node.js app
HEALTH_CHECK_URL="http://localhost:3000/health" # Example: Health check endpoint
HEALTH_CHECK_RETRIES=10
HEALTH_CHECK_DELAY=2 # seconds

start_service() {
    if [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE")" >/dev/null 2>&1; then
        echo "$SERVICE_NAME is already running (PID: $(cat "$PID_FILE"))."
        return 0
    fi

    echo "Starting $SERVICE_NAME..."
    eval "$START_CMD" # Use eval to execute the command with proper PID capture
    
    # Give service a moment to start and write PID
    sleep 2

    if [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE")" >/dev/null 2>&1; then
        echo "$SERVICE_NAME started with PID: $(cat "$PID_FILE")."
        check_health
    else
        echo "Failed to start $SERVICE_NAME. Check $LOG_FILE for details."
        return 1
    fi
}

stop_service() {
    if [ ! -f "$PID_FILE" ]; then
        echo "$SERVICE_NAME is not running (PID file not found)."
        return 0
    fi
    
    PID=$(cat "$PID_FILE")
    if kill -0 "$PID" >/dev/null 2>&1; then
        echo "Stopping $SERVICE_NAME (PID: $PID)..."
        kill "$PID" # Send SIGTERM for graceful shutdown
        
        # Wait for the process to terminate
        for i in $(seq 1 10); do
            if ! kill -0 "$PID" >/dev/null 2>&1; then
                echo "$SERVICE_NAME stopped."
                rm -f "$PID_FILE"
                return 0
            fi
            sleep 1
        done
        echo "Warning: $SERVICE_NAME (PID: $PID) did not terminate gracefully. Forcing kill."
        kill -9 "$PID" # Force kill if not stopped gracefully
        rm -f "$PID_FILE"
        return 1
    else
        echo "$SERVICE_NAME is not running (stale PID file found). Removing $PID_FILE."
        rm -f "$PID_FILE"
        return 0
    fi
}

restart_service() {
    stop_service
    sleep 2 # Give time for port release/cleanup
    start_service
}

check_health() {
    if [ -z "$HEALTH_CHECK_URL" ]; then
        echo "No health check URL configured for $SERVICE_NAME."
        return 0
    fi
    
    echo "Performing health check for $SERVICE_NAME at $HEALTH_CHECK_URL..."
    for i in $(seq 1 $HEALTH_CHECK_RETRIES); do
        HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$HEALTH_CHECK_URL")
        if [ "$HTTP_STATUS" -eq 200 ]; then
            echo "$SERVICE_NAME health check successful (HTTP 200)."
            return 0
        else
            echo "Health check attempt $i/$HEALTH_CHECK_RETRIES: HTTP Status $HTTP_STATUS. Retrying in $HEALTH_CHECK_DELAY seconds..."
            sleep "$HEALTH_CHECK_DELAY"
        fi
    done
    echo "Error: $SERVICE_NAME health check failed after $HEALTH_CHECK_RETRIES attempts."
    return 1
}

case "$1" in
    start)
        start_service
        ;;
    stop)
        stop_service
        ;;
    restart)
        restart_service
        ;;
    status)
        if [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE")" >/dev/null 2>&1; then
            echo "$SERVICE_NAME is running (PID: $(cat "$PID_FILE"))."
            check_health
        else
            echo "$SERVICE_NAME is not running."
            exit 1
        fi
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac
How it works: This comprehensive Bash script manages a service by handling start, stop, restart, and status commands. It uses a PID file to track the service's process ID, allowing for graceful termination (SIGTERM) before resorting to a forceful kill (SIGKILL). Additionally, it includes a configurable HTTP health check, crucial for verifying the service is truly operational after starting or restarting, making it ideal for managing web applications.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs