1

I need a second opinion and a sanity check if the solution I'm trying to implement will work.

I need to implement a way to run a script that would otherwise be blocking if I would run it using just ajax (and would probably timeout). So my idea is to do the following:

Have a button in the admin that, when clicked, would trigger an ajax call, which would schedule the event immediately. This scheduled event would be done using wp_schedule_event() (https://developer.wordpress.org/plugins/cron/scheduling-wp-cron-events/). In this event, on the first call, I'd add a flag in the database that will signal that the event is running. This is used as a way to check if the event is running in the background so that I can do a check, in ajax, if the job is running in the background - if it is, don't run it again.

Now, because it's a scheduled, recurring job, I'd need a way to not spawn it again all the time, even if it finished. What I was thinking is adding a check in the place where I add my add_action( 'bl_cron_hook', 'bl_cron_exec' ); hook for

if ( ! wp_next_scheduled( 'bl_cron_hook' ) ) {
    wp_schedule_event( time(), 'five_seconds', 'bl_cron_hook' );
}

The add_action call and the function to execute bl_cron_exec would be in a separate class, and the wp_schedule_event would be in the ajax callback.

And also, if the flag in the database is finished I would unschedule the job (in the class where the bl_cron_exec is).

What concerns me is, if my job is running in the background, and I unschedule the job, will this terminate the already running job, or am I safe and this job will continue working (or fail, in which case I will write to the db that the call failed). Because a running job is started in a separate process if I'm not mistaken. So a job that is running cannot be stopped, or can it?

Is there a smarter way of implementing background jobs in WordPress? I don't want a plugin, I need my own implementation (business reasons).

Basically, some kind of a flow would be:


ajax:

NO JOB RUNNING:

check if job is running - no
schedules event (in 1 sec or less)
triggers flag in the database - job running
exit with code - event started (scheduled)

JOB RUNNING:

check if job is running - yes
unschedule job
exit with code - event running

event:

If the database trigger says: running (the wp_next_scheduled should take care of that) - don't start new schedule (return? or unschedule).
If the database trigger says: finished, continue running the event.
  • What kind of job is it? Can the job be broken up into smaller parts that won't timeout? Does the solution need to be distributed to other WordPress installs, or it a one off site [because you can't control timeouts on regular WordPress installs]? – John Dee Oct 10 '19 at 17:38
  • 1
    No, unscheduling the even will not terminate a previous running job. It will prevent further items from being auto scheduled. – John Dee Oct 10 '19 at 17:38
  • It's an async code (using GuzzleHttp lib) that is running for quite a long time. I still need to check if the php max_execution_time won't kill it :S – dingo_d Oct 11 '19 at 9:52
1

I don't think you need to worry about this running flag or unscheduling. Since you are scheduling a one-time job that will run immediately there's no reason to unschedule it.

You just need to check if a job with that name is scheduled or not and if it is (even if it is running at the moment) don't do anything.

And yes, these jobs run on a different thread and as far as I know you can't cancel them midway.

so the flow would be:

  • Click button
  • Run Ajax in JS
  • PHP Callback checks if it's scheduled or not
  • If not, schedule it and return with wp_send_json_success().
    • Let it run
  • If it is, kill the ajax with wp_send_json_error()
|improve this answer|||||
  • Will try this. The flags are there because I don't want to run the job every X times (which is what wp-cron will do). So I need a way to unschedule the job once it's done – dingo_d Oct 10 '19 at 17:31
  • 1
    Sorry for the delay to get back on this. You can create non-recurring cron jobs with wp_schedule_single_event. developer.wordpress.org/reference/functions/… – Fernando Claussen Nov 26 '19 at 16:49
  • Yup this is what I ended up doing wp_schedule_single_event( time() - 1, $job_name ); – dingo_d Nov 27 '19 at 9:34
1

The way I do it, is to have three separate methods. One to start, one to stop, and one to do the process and check if it still should go.

interface WPCronBackgroundProcessManagerInterface {
    /**
     * @return boolean
     * determines if the condition to continue the process is still active
     * used to initiate the process, and determine if the process should continue
     */
    public function isProcessConditionActive();

    /**
     * @return bool; false for failure
     * @return bool; true for success
     */
    public function initiateProcess();

    /**
     * @return bool; false for failure
     * @return bool; true for success
     * This method should do the process, and check if it wants to keep going
     */
    public function continueProcess();
}
|improve this answer|||||
  • I was going with the same approach, creating an interface, then an abstract class so that I can reuse the code with different jobs (if needed in the future), and finally, make a concrete job. – dingo_d Oct 11 '19 at 9:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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