├── README.md └── action-scheduler-timeout-monitor.php /README.md: -------------------------------------------------------------------------------- 1 | ## Action Scheduler Timeout Monitor 2 | 3 | If a scheduled action runs for more than its allocated time (`action_scheduler_failure_period`) the `ActionScheduler_QueueCleaner` will mark the action as failed and log the nondescript error `action timed out after 300 seconds`. Because this cleaning event occurs in another PHP instance and separate process there's no stack trace which can be included as part of this error. 4 | 5 | This mini-extension keeps a record of where the action got caught up to help troubleshoot what's taking the action more than the 5 minutes (default) allowed. 6 | 7 | This plugin makes use of the resource intensive WP `'all'` action and therefore it is not recommended to have this plugin active for any longer than necessary. 8 | 9 | ### Installation 10 | 11 | 1. Upload the plugin's files to the `/wp-content/plugins/` directory of your WordPress site 12 | 1. Activate the plugin through the **Plugins** menu in WordPress 13 | 14 | #### License 15 | 16 | This plugin is released under [GNU General Public License v3.0](http://www.gnu.org/licenses/gpl-3.0.html). 17 | 18 | --- 19 | 20 |

21 | 22 |

23 | -------------------------------------------------------------------------------- /action-scheduler-timeout-monitor.php: -------------------------------------------------------------------------------- 1 | . 24 | * 25 | * @version 1.0 26 | * @package Action Scheduler Timeout Monitor 27 | * @author Prospress 28 | */ 29 | 30 | if ( ! defined( 'ABSPATH' ) ) { 31 | exit; // Exit if accessed directly 32 | } 33 | 34 | class Action_Scheduler_Timeout_Monitor { 35 | 36 | protected static $action_id = null; 37 | protected static $start_time = null; 38 | protected static $timeout_time = null; 39 | 40 | /** 41 | * Attach callbacks 42 | * 43 | * @since 1.0 44 | */ 45 | public static function init() { 46 | add_action( 'action_scheduler_before_execute', __CLASS__ . '::start_monitoring_action', 10 ); 47 | add_action( 'action_scheduler_after_execute', __CLASS__ . '::stop_monitoring_action', 10 ); 48 | } 49 | 50 | /** 51 | * Attach an 'all' action callback for monitoring execution times. 52 | * 53 | * @param int $action_id 54 | * @since 1.0 55 | */ 56 | public static function start_monitoring_action( $action_id ) { 57 | self::$action_id = $action_id; 58 | self::$start_time = microtime( true ); 59 | self::$timeout_time = self::$start_time + apply_filters( 'action_scheduler_failure_period', 5 * MINUTE_IN_SECONDS ); 60 | 61 | add_action( 'all', __CLASS__ . '::track_action_execution_time', 0 ); 62 | } 63 | 64 | /** 65 | * Detach 'all' action callbacks 66 | * 67 | * @since 1.0 68 | */ 69 | public static function stop_monitoring_action() { 70 | self::$action_id = self::$start_time = self::$timeout_time = null; 71 | 72 | remove_action( 'all', __CLASS__ . '::track_action_execution_time', 0 ); 73 | } 74 | 75 | /** 76 | * Detach 'all' action callbacks 77 | * 78 | * @since 1.0 79 | */ 80 | public static function track_action_execution_time( $value ) { 81 | $current_time = microtime( true ); 82 | 83 | if ( $current_time + 0.1 > self::$timeout_time ) { 84 | throw new Exception( sprintf( 'Scheduled action %s was about to timeout after %s', self::$action_id, $current_time - self::$start_time ) ); 85 | } 86 | 87 | return $value; 88 | } 89 | } 90 | Action_Scheduler_Timeout_Monitor::init(); 91 | --------------------------------------------------------------------------------