Introduction
PHP's max_execution_time directive limits how long a script can run before being terminated. While this protects web servers from runaway scripts, it can also affect CLI scripts if the directive is set in php.ini. Long-running cron jobs for data processing, report generation, or batch updates frequently exceed this limit.
This error causes cron jobs to fail silently or partially, leading to data inconsistency and missed scheduled operations.
Symptoms
- Cron script terminates with "Maximum execution time of 30 seconds exceeded"
- Script processes partial data before being killed
- Same script works when run manually with php -d max_execution_time=0
Common Causes
- max_execution_time is set globally in php.ini and applies to CLI scripts
- Script processes more data than anticipated due to database growth
- External API calls or network operations cause unexpected delays
Step-by-Step Fix
- 1.Set unlimited execution time for CLI scripts: Override the limit at the script start.
- 2.```php
- 3.<?php
- 4.// At the top of your cron script:
- 5.set_time_limit(0); // 0 = no time limit
// Or run with -d flag: // php -d max_execution_time=0 /path/to/cron.php ```
- 1.Use a separate php.ini for CLI with different limits: Configure CLI-specific settings.
- 2.```bash
- 3.# Check which php.ini CLI uses:
- 4.php --ini
- 5.# Output:
- 6.# Loaded Configuration File: /etc/php/8.2/cli/php.ini
# Edit the CLI php.ini (different from FPM/Apache php.ini): # /etc/php/8.2/cli/php.ini max_execution_time = 0 memory_limit = 512M ```
- 1.Implement progress tracking and resume capability: Make long scripts resumable.
- 2.```php
- 3.<?php
- 4.class ResumableProcessor {
- 5.private string $stateFile;
public function __construct(string $name) { $this->stateFile = "/tmp/{$name}_progress.json"; }
public function process(array $items): void { $processed = $this->loadProgress();
foreach ($items as $index => $item) { if ($index < $processed) continue; // Skip already processed
$this->processItem($item); $this->saveProgress($index + 1);
// Check execution time periodically if (connection_aborted()) { $this->cleanup(); exit; } }
$this->clearProgress(); }
private function loadProgress(): int { if (file_exists($this->stateFile)) { return (int)json_decode(file_get_contents($this->stateFile), true); } return 0; }
private function saveProgress(int $count): void { file_put_contents($this->stateFile, (string)$count); } } ```
Prevention
- Always set set_time_limit(0) at the start of cron scripts
- Use separate php.ini for CLI with appropriate limits
- Implement resumable processing with progress checkpoints
- Monitor cron job execution time and alert on unusually long runs