I recently needed to have a plugin re-try executing some code until the code executed successfully, and for this I thought that the “pseudo cron” scheduling feature of WordPress would be ideal.
I decided to try this out on one of my hosting servers, and I’m glad I did. To my puzzlement the scheduling code just wouldn’t work… what the heck was going wrong?!?!
Finding the cause
After instrumenting the WordPress source code I finally narrowed down the cause… the paranoid security configuration of my hosting company.
This is a problem?!?! Well the trouble is that the “cron” code depends on PHP’s fsockopen() network function. The WordPress code uses this function to run the code in the wp-cron.php file, and it is this code which looks at the events that have been scheduled and tries to carry them out.
Since fsockopen() is blocked from working, even from making connections looping back to the same server, so to is the whole “pseudo cron” event scheduling feature of WordPress. So if you need to have code that runs at regular intervals e.g. database backup, creating RSS feeds, sending out newsletters etc. you may face a rude shock.
A solution ?
In the ideal world I’d expect that WordPress would provide a fallback mechanism for servers that have this problem, however in the real world I’m not so optimistic. I haven’t checked how prevalent this problem may be so for now I’m documenting this issue in case others are scowering the internet for answers.
For coders who must absolutely rely on this “psuedo cron” there may be a workaround. I’ve found that in the WordPress code there is a short-circuit that will call a callback function instead of attempting to execute the wp-cron.php code. To do this you need to do the following (see the code sample below):
- Create a callback function to schedule that returns false
- Register a custom “schedule interval” by overriding the ‘cron_schedules’ filter
- Schedule a single event
function my_callback()
{
// Do something here...
//
// VERY IMPORTANT:
//
// If this is a single event you will need to "unschedule" the event
// at this point. To do this you will need to store all of the values
// that you need to pass to wp_unschedule_event(...) such as
// the time the event is scheduled for, the hook name (in this
// example 'my_schedule_hook_name'), and any optional
// parameters.
//
// Also make sure that this function returns false otherwise the
// short-circuit won't work.
//
return false;
}
function my_schedules($wp_schedules)
{
$new_schedules = $wp_schedules;
$new_schedules['my_schedule_hook_name'] =
array('interval' => 86400, 'display' => __('My Interval Name'), 'callback' => 'my_callback');
return $new_schedules;
}
//
add_filter('cron_schedules', 'my_schedules');
// Trigger the scheduling on a daily basis - Note for plugins do this
// somewhere where it won't execute each time the plugin is loaded
// since plugins are loaded each time a page is refreshed.
wp_schedule_single_event(time() + 86400, 'my_schedule_hook_name');
Hopefully this workaround that I’ve found will help you build more robust code. Please let me know how you go.
November 12th, 2008 at 3:58 am
Good post.