FIX: Critical subshell scope bug - CRON_OFFSET not persisting across iterations
The staggered cron scheduling was completely broken due to bash subshell scope
issue. The pattern was:
cron_time=$(generate_staggered_cron) # Creates subshell!
This caused CRON_OFFSET to increment in the subshell but not persist to the
parent shell, resulting in ALL 200 sites getting cron time 0 * * * *.
BEFORE (broken):
All 200 sites → 0 * * * * (massive load spikes!)
AFTER (fixed):
Sites distributed as: 0, 3, 6, 9, 12, ... 57 (repeats)
200 sites: 10 sites per time slot (perfect distribution)
Solution: Changed from command substitution to global variable approach:
- generate_staggered_cron now sets LAST_CRON_TIME instead of echo
- Callers read $LAST_CRON_TIME after function call
- CRON_OFFSET increments now properly persist across loop iterations
Fixed three locations:
- Option 2: disable for domain
- Option 3: disable for user
- Option 4: disable server-wide
All 200 sites will now run with proper load distribution across the hour.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -201,6 +201,9 @@ BATCH_MODE=false
|
||||
# Global counter for staggering cron times
|
||||
CRON_OFFSET=0
|
||||
|
||||
# Global variable to hold generated cron time (avoids subshell scope issues)
|
||||
declare -g LAST_CRON_TIME=""
|
||||
|
||||
# PERFORMANCE OPTIMIZATION: Global cache for find results
|
||||
# Instead of running find 23 times, run once and reuse results
|
||||
declare -g WP_SITES_CACHE=""
|
||||
@@ -1421,6 +1424,7 @@ 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
|
||||
# NOTE: Uses global variable LAST_CRON_TIME instead of echo to avoid subshell issues
|
||||
|
||||
# Calculate staggered minute (0-59) - each site gets a different minute
|
||||
local minute=$((CRON_OFFSET % 60))
|
||||
@@ -1431,12 +1435,12 @@ generate_staggered_cron() {
|
||||
local stagger_minute=$((minute * 3))
|
||||
stagger_minute=$((stagger_minute % 60))
|
||||
|
||||
# Increment offset for next site
|
||||
# Increment offset for next site (THIS PERSISTS in parent shell, not in subshell)
|
||||
CRON_OFFSET=$((CRON_OFFSET + 1))
|
||||
|
||||
# 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 * * * *"
|
||||
# Set global variable instead of using echo (avoids subshell scope issue)
|
||||
# This ensures CRON_OFFSET increments persist across loop iterations
|
||||
LAST_CRON_TIME="$stagger_minute * * * *"
|
||||
}
|
||||
|
||||
# Function to extract user from WordPress site path
|
||||
@@ -1968,7 +1972,8 @@ case "$choice" in
|
||||
fi
|
||||
|
||||
# Generate staggered cron time and add to crontab
|
||||
cron_time=$(generate_staggered_cron)
|
||||
generate_staggered_cron # Sets LAST_CRON_TIME globally (avoids subshell)
|
||||
cron_time="$LAST_CRON_TIME"
|
||||
if safe_add_cron_job "$user" "$cron_time" "$cron_cmd"; then
|
||||
echo -e "${GREEN}✓${NC} Added cron job ($cron_time)"
|
||||
else
|
||||
@@ -2091,7 +2096,8 @@ case "$choice" in
|
||||
fi
|
||||
|
||||
if ! cron_job_exists "$user" "$site_path"; then
|
||||
cron_time=$(generate_staggered_cron)
|
||||
generate_staggered_cron # Sets LAST_CRON_TIME globally (avoids subshell)
|
||||
cron_time="$LAST_CRON_TIME"
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo " [DRY-RUN] Would add cron job ($cron_time)"
|
||||
else
|
||||
@@ -2212,7 +2218,8 @@ case "$choice" in
|
||||
cron_cmd=$(build_cron_command "$site_path")
|
||||
|
||||
if ! cron_job_exists "$user" "$site_path"; then
|
||||
cron_time=$(generate_staggered_cron)
|
||||
generate_staggered_cron # Sets LAST_CRON_TIME globally (avoids subshell)
|
||||
cron_time="$LAST_CRON_TIME"
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo " [DRY-RUN] Would add cron job ($cron_time)"
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user