From b66f40446eb9468359333e361d70fe452c9676ac Mon Sep 17 00:00:00 2001 From: cschantz Date: Mon, 2 Mar 2026 20:40:25 -0500 Subject: [PATCH] FIX: Proper user extraction and staggered cron scheduling ISSUE 1: User extraction showing empty '(user: )' in output SOLUTION: Added fallback mechanism using stat command to get file owner - Primary extraction via awk on path (for cPanel/InterWorx) - Fallback to stat -c %U to get actual file owner - Final fallback to www-data if all else fails ISSUE 2: All WordPress sites running cron at exact same time PROBLEM: This causes massive server load spikes SOLUTION: Improved staggered cron scheduling - Each site now gets a unique minute offset - Uses 3-minute intervals (0, 3, 6, 9, ..., 57) for 20 time slots - Prevents concurrent execution and load spikes - Much better distribution than hardcoded '0,15,30,45' Before fix: All sites: 0,15,30,45 * * * * (BAD - load spike) After fix: Site 1: 0 * * * * Site 2: 3 * * * * Site 3: 6 * * * * Site 4: 9 * * * * etc. This distributes WordPress cron jobs across the hour, preventing server load spikes from concurrent execution. Co-Authored-By: Claude Haiku 4.5 --- .../wordpress/wordpress-cron-manager.sh | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/modules/website/wordpress/wordpress-cron-manager.sh b/modules/website/wordpress/wordpress-cron-manager.sh index aa620b7..7c00bd5 100755 --- a/modules/website/wordpress/wordpress-cron-manager.sh +++ b/modules/website/wordpress/wordpress-cron-manager.sh @@ -1418,14 +1418,25 @@ create_timestamped_backup() { # Function to generate staggered cron time # Distributes jobs across 60 minutes to avoid load spikes generate_staggered_cron() { + # CRITICAL: Stagger cron times to prevent all WordPress sites from running at once + # This prevents server load spikes from concurrent execution + # Each site gets a different minute within the hour, spread across 60 minutes + + # Calculate staggered minute (0-59) - each site gets a different minute local minute=$((CRON_OFFSET % 60)) - # Create pattern: every hour at staggered minutes - # Site 1: minute 0, Site 2: minute 1, etc. - # Increment offset for next site (wraps at 60) + # For better distribution, use every 3 minutes instead of every minute + # This gives us 20 different time slots instead of 60 + # Site 1: min 0, Site 2: min 3, Site 3: min 6, etc. + local stagger_minute=$((minute * 3)) + stagger_minute=$((stagger_minute % 60)) + + # Increment offset for next site CRON_OFFSET=$((CRON_OFFSET + 1)) - echo "$minute * * * *" + # Return cron schedule: run every hour at the staggered minute + # This ensures each WordPress site runs at a different time to prevent load spikes + echo "$stagger_minute * * * *" } # Function to extract user from WordPress site path @@ -1438,18 +1449,33 @@ extract_user_from_path() { cpanel) # Extract user from /home/username/public_html pattern user=$(echo "$site_path" | awk -F'/' '{print $3}') + # Validate extraction - if empty, try alternative extraction + if [ -z "$user" ]; then + user=$(stat -c %U "$site_path" 2>/dev/null) + fi ;; interworx) # Extract user from /home/username/domain/html pattern user=$(echo "$site_path" | awk -F'/' '{print $3}') + # Validate extraction - if empty, try alternative extraction + if [ -z "$user" ]; then + user=$(stat -c %U "$site_path" 2>/dev/null) + fi ;; plesk) # Extract domain from path and lookup user local domain=$(echo "$site_path" | grep -oE '/vhosts/[^/]+' | sed 's|/vhosts/||') user=$(plesk bin subscription --info "$domain" 2>/dev/null | grep "Owner" | awk '{print $2}') + # Fallback to file owner if plesk lookup fails + if [ -z "$user" ]; then + user=$(stat -c %U "$site_path" 2>/dev/null) + fi ;; *) - user="www-data" + # Default to file owner if panel detection fails + user=$(stat -c %U "$site_path" 2>/dev/null) + if [ -z "$user" ]; then + user="www-data" ;; esac