Skip to content

Deferred Mode Implementation

Deferred mode allows the REST API endpoint to respond immediately (HTTP 202 Accepted) while processing cron jobs in the background. This prevents timeout issues on large networks and improves integration with external systems.

Add the defer=1 parameter to any REST API call:

Terminal window
# JSON mode with defer
curl https://example.com/wp-json/all-sites-cron/v1/run?defer=1
# GitHub Actions mode with defer
curl https://example.com/wp-json/all-sites-cron/v1/run?ga=1&defer=1
Client Request → REST Handler → Immediate Response (HTTP 202)
Background Processing
Cron Jobs Execute
Log Results

The plugin uses different methods based on webserver configuration:

if ( function_exists( 'fastcgi_finish_request' ) ) {
// Send response
echo wp_json_encode( $response->get_data() );
// Close connection
fastcgi_finish_request();
// Continue processing in background
( new \Soderlind\Multisite\AllSitesCron\Cron_Runner() )->run_all_sites();
}

Supported Environments:

  • Nginx + PHP-FPM ✅
  • Apache + mod_fcgid ✅
  • Litespeed ✅
// Flush output buffers
ob_start();
echo wp_json_encode( $response->get_data() );
header('Connection: close');
header('Content-Length: ' . ob_get_length());
ob_end_flush();
flush();
// Continue processing
( new \Soderlind\Multisite\AllSitesCron\Cron_Runner() )->run_all_sites();

Supported Environments:

  • Apache + mod_php ⚠️ (works but less reliable)
  • Most shared hosting ⚠️ (depends on configuration)
EnvironmentMethodNotes
Nginx + PHP-FPMFastCGIBest performance, cleanest connection closure
Apache + mod_fcgidFastCGIExcellent performance
LitespeedFastCGIFull support with Litespeed API
EnvironmentMethodNotes
Apache + mod_phpFallbackWorks but connection may not close immediately
Shared HostingFallbackDepends on hosting provider’s PHP configuration
EnvironmentIssue
CGI modeCannot close connection early
Hosting with aggressive timeoutsMay kill long-running processes
Terminal window
php -r "echo function_exists('fastcgi_finish_request') ? 'FastCGI: YES' : 'FastCGI: NO';"
Terminal window
# Time the request (should return immediately)
time curl -X GET "https://example.com/wp-json/all-sites-cron/v1/run?defer=1"
# Expected: < 1 second response time
# Actual processing continues in background

Monitor your server logs for completion message:

Terminal window
tail -f /path/to/php-error.log | grep "All Sites Cron"
# Expected output:
# [All Sites Cron] Deferred execution completed: 150 sites processed
{
"success": true,
"status": "queued",
"message": "Cron job queued for background processing",
"timestamp": "2025-10-01 12:00:00",
"mode": "deferred"
}

HTTP Status: 202 Accepted

::notice::Cron job queued for background processing

HTTP Status: 202 Accepted

{
"success": true,
"count": 150,
"message": "",
"timestamp": "2025-10-01 12:00:05",
"endpoint": "rest"
}

HTTP Status: 200 OK

  1. Large Networks (100+ sites)

    • Prevents REST API timeouts
    • Allows processing to complete without client waiting
  2. GitHub Actions / CI/CD

    • Workflow completes quickly
    • No timeout errors
    • Can run more frequently
  3. External Monitoring Services

    • Services that expect quick responses
    • Pingdom, UptimeRobot, cron-job.org, etc.
  4. Load Balancers

    • Prevents timeout at load balancer level
    • Better health check responses
  1. Small Networks (< 50 sites)

    • Synchronous mode is fast enough
    • No benefit from deferred processing
  2. Debugging / Testing

    • Synchronous mode provides immediate feedback
    • Easier to see errors and results
  3. Sequential Dependencies

    • If you need to wait for completion before next action
    • Synchronous mode ensures completion
name: All Sites Cron Job
on:
schedule:
- cron: '*/5 * * * *' # Every 5 minutes
env:
CRON_ENDPOINT: 'https://example.com/wp-json/all-sites-cron/v1/run?ga=1&defer=1'
jobs:
trigger_cron:
runs-on: ubuntu-latest
timeout-minutes: 2 # Can be reduced with defer mode
steps:
- name: Trigger Cron
run: |
curl -X GET ${{ env.CRON_ENDPOINT }} \
--connect-timeout 10 \
--max-time 30 \
--retry 3 \
--retry-delay 5 \
--silent \
--show-error \
--fail
  • ✅ Prevents workflow timeout errors
  • ✅ Faster workflow completion
  • ✅ More reliable execution
  • ✅ Can reduce timeout-minutes setting
  • ✅ Lower GitHub Actions billing (faster = cheaper)
ModeNetwork SizeResponse TimeTotal TimeBest For
Synchronous50 sites5 seconds5 secondsSmall networks
Synchronous200 sites20 seconds20 secondsMedium networks
Synchronous500 sites50 seconds50 secondsRisk of timeout
Deferred50 sites< 1 second5 seconds*External triggers
Deferred200 sites< 1 second20 seconds*GitHub Actions
Deferred500 sites< 1 second50 seconds*Large networks

* Total time happens in background; client doesn’t wait

Symptom: Request takes full processing time despite defer=1

Solutions:

  1. Check if fastcgi_finish_request() exists:

    Terminal window
    php -r "var_dump(function_exists('fastcgi_finish_request'));"
  2. Verify PHP-FPM is being used:

    Terminal window
    php -i | grep "Server API"
    # Should show: FPM/FastCGI
  3. Check for output buffering conflicts in wp-config.php

Issue: “Process killed during background execution”

Section titled “Issue: “Process killed during background execution””

Symptom: Cron doesn’t complete on all sites

Solutions:

  1. Increase PHP timeout in php.ini:

    max_execution_time = 300
  2. Check for hosting-level process restrictions

  3. Consider reducing all_sites_cron_batch_size filter

Symptom: Can’t see completion message in logs

Solutions:

  1. Enable PHP error logging in php.ini:

    log_errors = On
    error_log = /path/to/php-error.log
  2. Check WordPress debug log if WP_DEBUG_LOG is enabled

  3. Verify file permissions on log file

  1. Authentication (v2.0.0): Optionally protect endpoints with a shared-secret token — see Authentication
  2. No Additional Risk: Deferred mode uses same permissions as synchronous mode
  3. Rate Limiting: Still applies (60-second default cooldown)
  4. Request Locking: Atomic lock prevents concurrent executions
  5. Log Monitoring: Background execution is logged for auditing

Potential improvements for future versions:

  • Queue system with Redis storage (added in v1.5.0, improved in v2.0.0)
  • Status endpoint to check background job progress
  • Webhook callbacks when processing completes
  • Priority queue for specific sites
  • Progress tracking API

If you encounter issues with deferred mode:

  1. Check this documentation first
  2. Test your environment compatibility
  3. Review server logs for errors
  4. Open an issue on GitHub with:
    • PHP version
    • Webserver type and version
    • Hosting environment
    • Error logs