Server Deployment Safety: The Essential Envoyer Resource Check Script
Deploying new code to a production server is a high-stakes operation. Even with automated tools like Laravel Envoyer, a deployment that kicks off while the server is already struggling under heavy load can lead to degraded performance, cascading errors, and even downtime.
The solution is a pre-deployment resource gate. By running a simple check before deployment hooks are executed, you can instantly verify that the server has sufficient capacity, safeguarding your application's stability.
Why Server Health Checks are Critical for Deployments
A typical deployment process is resource-intensive, temporarily spiking the usage of your server's core components:
- Composer Operations: High CPU and intense disk I/O.
- Asset Compilation (Vite/Mix): Heavy CPU and Memory utilization.
- Cache & Configuration Clearing: Brief, high-frequency I/O operations.
If a server is nearing its capacity (e.g., memory exhaustion or high load average) due to organic traffic, these deployment tasks can push the system past its limit, resulting in slow responses or failure states for end-users.
The Envoyer Deployment Resource Check Script
This Bash script performs four critical resource evaluations and will immediately halt the Envoyer deployment if any threshold is exceeded (by exiting with code 1).
1#!/bin/bash 2 3# ================================================================= 4# Envoyer Deployment Safety Check 5# Checks critical server resources before allowing a deployment. 6# Exit code 1 prevents deployment. 7# ================================================================= 8 9# --- Configuration: Adjust these thresholds as needed --- 10 11# 1. Memory Check 12# Maximum percentage of truly USED memory (excluding buffers/cache). 13# Using 'available' memory relative to total memory is often more reliable. 14MAX_MEMORY_USED_PERCENT=85 15 16# 2. CPU Check 17# Maximum percentage of CPU usage. 18MAX_CPU_PERCENT=80 19 20# 3. Load Average Check 21# Maximum 1-minute load average allowed (scaled by the number of CPU cores). 22# Formula: MAX_LOAD_AVERAGE = MAX_LOAD_MULTIPLIER * CPU_CORES 23MAX_LOAD_MULTIPLIER=1.0 # 1.0 means average load can equal the number of cores 24 25# 4. Disk Space Check 26# Maximum percentage of disk usage allowed on the root filesystem. 27TARGET_DISK_PATH="/" 28MAX_DISK_USAGE_PERCENT=90 29 30 31# ================================================================= 32# --- Resource Collection --- 33# ================================================================= 34 35# 1. Get CPU Cores Count (used for scaling Load Average check) 36CPU_CORES=$(grep -c ^processor /proc/cpuinfo) 37 38# 2. Get Memory Usage Percentage (Modern Linux: Uses 'available' for true capacity) 39# We calculate (Total - Available) / Total * 100 40MEMORY_TOTAL_KB=$(free -k | grep Mem | awk '{print $2}') 41MEMORY_AVAILABLE_KB=$(free -k | grep Mem | awk '{print $7}') 42MEMORY_USED_KB=$(($MEMORY_TOTAL_KB - $MEMORY_AVAILABLE_KB)) 43 44if [ "$MEMORY_TOTAL_KB" -eq 0 ]; then 45 MEMORY_USAGE=0 46else 47 # Calculate Memory Usage % (avoiding floating point math for pure Bash) 48 MEMORY_USAGE=$((MEMORY_USED_KB * 100 / MEMORY_TOTAL_KB)) 49fi 50 51# 3. Get CPU Usage Percentage 52# vmstat 1 2 gives two reports, we take the last line's idle percentage (id) 53# and calculate 100 - idle. 54CPU_IDLE=$(vmstat 1 2 | tail -1 | awk '{print $15}') 55CPU_USAGE=$((100 - CPU_IDLE)) 56 57# 4. Get 1-Minute Load Average 58LOAD_AVG_1MIN=$(uptime | awk -F'load average: ' '{ print $2 }' | cut -d',' -f1 | tr -d '[:space:]') 59# Calculate the max allowed load based on cores 60MAX_LOAD_ALLOWED=$(echo "$CPU_CORES * $MAX_LOAD_MULTIPLIER" | bc -l) 61 62# 5. Get Disk Usage Percentage for the target path 63DISK_USAGE=$(df -h "$TARGET_DISK_PATH" | tail -1 | awk '{print $5}' | sed 's/%//') 64 65 66echo "--- Server Resource Check ---" 67echo "System Cores: ${CPU_CORES}" 68echo "Max Load Allowed (1m): ${MAX_LOAD_ALLOWED}" 69echo "" 70echo "Current Memory Usage (Used/Total): ${MEMORY_USAGE}% (Max: ${MAX_MEMORY_USED_PERCENT}%)" 71echo "Current CPU Usage (User/System): ${CPU_USAGE}% (Max: ${MAX_CPU_PERCENT}%)" 72echo "Current Load Average (1m): ${LOAD_AVG_1MIN} (Max: ${MAX_LOAD_ALLOWED})" 73echo "Current Disk Usage (${TARGET_DISK_PATH}): ${DISK_USAGE}% (Max: ${MAX_DISK_USAGE_PERCENT}%)" 74echo "-----------------------------" 75 76# ================================================================= 77# --- Threshold Checks --- 78# ================================================================= 79 80EXIT_CODE=0 81 82# Check 1: Memory 83if [ "$MEMORY_USAGE" -gt "$MAX_MEMORY_USED_PERCENT" ]; then 84 echo "[ERROR]: Memory usage (${MEMORY_USAGE}%) exceeds threshold (${MAX_MEMORY_USED_PERCENT}%)" 85 EXIT_CODE=1 86fi 87 88# Check 2: CPU 89if [ "$CPU_USAGE" -gt "$MAX_CPU_PERCENT" ]; then 90 echo "[ERROR]: CPU usage (${CPU_USAGE}%) exceeds threshold (${MAX_CPU_PERCENT}%)" 91 EXIT_CODE=1 92fi 93 94# Check 3: Load Average 95# Use 'bc' for floating point comparison 96if echo "$LOAD_AVG_1MIN > $MAX_LOAD_ALLOWED" | bc -l | grep -q 1; then 97 echo "[ERROR]: Load Average (${LOAD_AVG_1MIN}) exceeds core-scaled threshold (${MAX_LOAD_ALLOWED})" 98 EXIT_CODE=1 99fi100 101# Check 4: Disk Space102if [ "$DISK_USAGE" -ge "$MAX_DISK_USAGE_PERCENT" ]; then103 echo "[ERROR]: Disk usage (${DISK_USAGE}%) exceeds threshold (${MAX_DISK_USAGE_PERCENT}%) on ${TARGET_DISK_PATH}"104 EXIT_CODE=1105fi106 107 108# --- Final Result ---109if [ "$EXIT_CODE" -eq 0 ]; then110 echo "[PASS]: Resource check passed - safe to deploy."111else112 echo "[FAIL]: Deployment halted due to critical resource constraints."113fi114 115exit $EXIT_CODE
Key Metrics and Logic
The script checks four primary indicators of server health:
Metric | Checks For | Measurement Method | Safety Logic |
---|---|---|---|
Memory Usage | True Memory Consumption | Calculates percentage of used RAM (excluding buffers/cache) based on free -k . |
Fails if used memory exceeds $MAX_MEMORY_USED_PERCENT . |
CPU Usage | Instantaneous CPU Activity | Measures current system CPU use based on vmstat . |
Fails if CPU usage exceeds $MAX_CPU_PERCENT . |
Load Average (1m) | Overall System Stress | The number of processes waiting for CPU time. Scaled by the number of CPU cores. | Fails if Load Average exceeds the calculated $MAX_LOAD_ALLOWED (Core Count x Multiplier). |
Disk Usage | Storage Space Availability | Measures percentage use of the target filesystem (default is / ). |
Fails if disk utilization exceeds $MAX_DISK_USAGE_PERCENT . |
Integrating the Script into Envoyer
The script should be added as the first (or one of the first) deployment hook in your Envoyer project settings to ensure resource checks happen before any deployment operations begin.
- Envoyer Hook: In your Envoyer project's Hooks section, create a new deployment hook and paste the script contents directly into the hook. Make sure this hook runs first to gate the deployment before other operations execute.
Customizing Safety Thresholds
The script's sensitivity can be tuned by editing the configuration variables at the top of the script before pasting it into Envoyer:
1# Maximum percentage of truly USED memory2MAX_MEMORY_USED_PERCENT=853 4# Maximum 1-minute load average allowed (1.0 = equal to number of cores)5MAX_LOAD_MULTIPLIER=1.06 7# Maximum percentage of disk usage allowed on the root filesystem8MAX_DISK_USAGE_PERCENT=90
Understanding the Max Load Multiplier
The MAX_LOAD_MULTIPLIER
is the most important variable for controlling the deployment gate under high traffic.
The Load Average is a metric that represents the average number of processes actively using or waiting for the CPU. A load average equal to the number of CPU cores means the system is fully utilized—there is no spare capacity.
The script calculates the allowed threshold using the formula:
1MAX_LOAD_ALLOWED = CPU_CORES × MAX_LOAD_MULTIPLIER
Setting Guidelines:
Multiplier Value | Interpretation | Effect on Deployment |
---|---|---|
0.7 to 0.8 | Conservative | Deployment is only allowed when the server has significant spare capacity (20% to 30% idle). Recommended for high-traffic, latency-sensitive applications. |
1.0 (Default) | Standard | Deployment is allowed as long as the system is not actively queuing processes. This means all CPU cores are busy, but no tasks are waiting in line. |
1.2 to 1.5 | Aggressive | Deployment is allowed even if the server is queuing a few extra processes. Use only for low-traffic applications or deployments that are known to be very fast. |
Recommendation: Start with the default 1.0
. Monitor your server's typical load average during peak hours. If you notice deployments occasionally fail during acceptable traffic spikes, slowly reduce the multiplier (e.g., to 0.8
or 0.9
) to be more conservative.
By setting these limits, you gain granular control over when the deployment pipeline considers the server "safe" to proceed, adding a vital layer of protection to your production workflow.