7

I have around 20 wp_cron() functions like the following code. Almost all crons run hourly; a few are daily.

if ( ! wp_next_scheduled( 'my_task_hook' ) ) {
  wp_schedule_event( time(), 'hourly', 'my_task_hook' );
}

add_action( 'my_task_hook', 'my_task_function' );

function my_task_function() {
  //Complex Code
}

To increase server performance, and so as not to keep getting server limit messages from hosting companies, I want to make sure that only one cron runs at a given time... Is it possible?


The current accepted answer is great, but I have following question, that's why I start a bounty for this question.

Please read the accepted answer at first.

Let assume Cron 1 runs, My code of cron2 won't running because still we are inside the 5 minute or first cron is running still, but because of wp_schedule_event( time(), 'hourly', 'my_task_hook' ); running for cron2 I think WordPress consider as cron2 runs..... So basically code of cron2 code never run..... Or I have misunderstand something?

  • No, you understand it correctly. I'll update my answer with some solutions for your problem... – Krzysiek Dróżdż Jul 24 '18 at 19:04
8

Yes, it is possible...

And to be honest, it's often very important to do this... WP Scheduler sometimes tends to cause problems, when cron tasks are long...

So how I solve this problem?

I use Transients API to implement semaphores...

Here's the code:

if ( ! wp_next_scheduled( 'my_task_hook' ) ) {
  wp_schedule_event( time(), 'hourly', 'my_task_hook' );
}

add_action( 'my_task_hook', 'my_task_function' );

function my_task_function() {
  // if some other my_task is already running, stop
  if ( get_transient( 'my_task_function_semaphore' ) ) return;

  // set semaphore for 5 minutes
  set_transient( 'my_task_function_semaphore', true, 5*60 );

  // DO YOUR STUFF

  delete_transient( 'my_task_function_semaphore' );
}

Why do I use transients in this case? Because:

  • They're part of WP.
  • They're easy to use and efficient.
  • They won't cause deadlocks. Let's say my cron task can get killed (some error may occur, or it runs too long and gets killed, and so on). In such case it won't delete semaphore, so all future tasks won't work. Using transients solves this problem, because after some time transient will be deleted.

And what if there are many different actions to do?

So let's say there are many different cron tasks, that should never run in same time, but we still want them all to run...

If we use the solution with semaphore and use only one semaphore for all of these tasks, then some of them may never run. So what to do then?

In such case you should change your thinking. You don't have some independent tasks, but a queue of tasks to do. So you should implement it in this way.

So:

  1. You add some kind of queue (you can use an array and store it as option, or add a custom DB table).
  2. You use your currently WP cron hourly event to add tasks to queue.
  3. You add second WP cron tasks which runs much more often and it "eats" tasks from queue one by one. This "eater" task should use semaphore to ensure that only one task runs at a moment.
  • Thanks, but I am sorry, I never used transient before... But I am tring to understand the code. Why did you set 5 minutes for transient because you delete the transient using delete_transient(). So that time matters? I mean which ever time you put to set_transient, it is deleted just after the my work is done... So why there is a time? – I am the Most Stupid Person Jul 17 '18 at 9:22
  • Because some errors may occur. Take a look at the last bullet point. – Krzysiek Dróżdż Jul 17 '18 at 9:24
  • Thanks, great... Just one question. As I understand, If I use my_task_function_semaphore as the name for transient, I must use all other crons to the same name? – I am the Most Stupid Person Jul 17 '18 at 9:28
  • @IamtheMostStupidPerson it depends on what you want to achieve... If only one task should work in given moment, then yes - all tasks should use the same transient name as semaphore – Krzysiek Dróżdż Jul 17 '18 at 9:29
  • 1
    I've done similar things with Job Queue tools like Gearman. This implementation may help: github.com/10up/WP-Minions – Fayaz Jul 24 '18 at 19:26

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.