Jose Jimenez
Jose Jimenez
Software Architect & Developer
> >

Server Deployment Safety: The Essential Envoyer Resource Check Script

Published in Envoyer, Forge, Devops on Oct 3, 2025

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
 99fi
100 
101# Check 4: Disk Space
102if [ "$DISK_USAGE" -ge "$MAX_DISK_USAGE_PERCENT" ]; then
103 echo "[ERROR]: Disk usage (${DISK_USAGE}%) exceeds threshold (${MAX_DISK_USAGE_PERCENT}%) on ${TARGET_DISK_PATH}"
104 EXIT_CODE=1
105fi
106 
107 
108# --- Final Result ---
109if [ "$EXIT_CODE" -eq 0 ]; then
110 echo "[PASS]: Resource check passed - safe to deploy."
111else
112 echo "[FAIL]: Deployment halted due to critical resource constraints."
113fi
114 
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.

  1. 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 memory
2MAX_MEMORY_USED_PERCENT=85
3 
4# Maximum 1-minute load average allowed (1.0 = equal to number of cores)
5MAX_LOAD_MULTIPLIER=1.0
6 
7# Maximum percentage of disk usage allowed on the root filesystem
8MAX_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.