4

I have a custom post type ('my_cpt') and upon save_post_my_cpt I need to possibly make a large number of modifications to other posts (depending on the state of the post, e.g., post_status, post_meta values and terms from custom taxonomy). These other modifications might need to be made in other blogs in a multisite. Hence, the function called on save_post_my_cpt might take up to a minute or so to complete execution...which isn't very "user friendly" for the admin user doing the content changes.

I'm setting things up so that these other modifications happen via WP Cron. So I have:

add_action ('save_post_my_cpt', 'save_cpt') ;

function
save_cpt ($post_id)
{
    if (defined ('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return ;
        }

    // do stuff related to saving post meta, etc
    // e.g., update_post_meta ($post_id, '_some_meta_name', $_REQUEST['some_meta_name'], true) ;

    // schedule an event to do the modifications of other posts
    // see below for question related to the time this cron job will be scheduled
    $time = time () ;
    wp_schedule_single_event ($time, 'my_cron_hook', array ($post_id)) ;

    return ;
}

add_action ('my_cron_hook', 'cron_func') ;

function
cron_func ($post_id)
{
    $post = get_post ($post_id) ;

    // get_blogs_that_might_need_to_be_modified() returns an array of blog_id's that
    // MIGHT have other posts related to $post that need to be modified

    // get_posts_in_that_blog_that_need_to_be_modified() returns an array of posts
    // related to $post that need to be modified

    // modify_post() returns a modified version of a related post based on the
    // current state of $post

    // the details of these functions aren't relevant to this question
    foreach (get_blogs_that_might_need_to_be_modified ($post) as $blog_id) {
        switch_to_blog ($blog_id) ;

        foreach (get_posts_in_that_blog_that_need_to_be_modified ($post) as $other_post) {
            $other_post = modify_post ($post) ;
            wp_update_post ($other_post) ;
            }

        restore_current_blog () ;
        }
}

Hopefully, everyone is with me up to this point. My question has to do with the time at which I should schedule this 1 time cron job.

If I schedule the cron job to run "immediately" (as in the code above), can I be assured that by the time cron_func() is called that ALL of the DB updates related to the saving of my CPT will have completed (since the funcs called in cron_func() will need to read the modified state of $post_id)?

Scheduling the event to run "immediately" seems to work fine in my local development environment (where I'm the only one hitting the site).

I'm wondering if I'll likely have any problems doing things this way when the site is running in a heavy activity production environment (i.e., with a number of admin users simultanously editing content on the back end, while a fair number of end-users are hitting the front end)

Two alternatives I'm considering:

  1. add some offset to time() when scheduling the event?
    1. e.g., schedule it to run 1 minute later
    2. if I need to do this, any guesses as to how long I should wait
  2. gather all of the info I need in save_cpt() and pass it in the $args param to wp_schedule_single_event()
    1. I would prefer not to go this route, as gathering that info could itself take a while, which would slow things down for the admin user
    2. is there "expense" (i.e., memory/etc) in passing a large amount of info to a job via cron?

Are there any other considerations that I should be accounting for? For example, what is likely the happen when:

  1. admin user A edits post X, which schedules the cron job
  2. before that cron job finishes, admin user B makes another edit to post X
1

If I schedule the cron job to run "immediately" (as in the code above), can I be assured that by the time cron_func() is called that ALL of the DB updates related to the saving of my CPT will have completed (since the funcs called in cron_func() will need to read the modified state of $post_id)

Yes. save_post hook is fired after the post has been actually saved. So, the cron_func will get the modified state of the post. You don't need any alternative for this.

Are there any other considerations that I should be accounting for? For example, what is likely the happen when:

  1. admin user A edits post X, which schedules the cron job before that cron job finishes,
  2. admin user B makes another edit to post X

If the cron job take some time, it's very possible to encounter such an issue. To solve this issue, you might raise a flag(it can be a post meta) when creating the cron task and clear the flag when cron task finishes. You might want to disable editing of the post as long as the flag is present for a post.

  • thanx. On the 1st point: I know that do_action ("save_post_{$post->post_type}") is done at the very end of wp_insert_post(). I guess my question is: are the $wpdb operations "blocking", that is, could $wpdb->update() possibly return before the db server (which is a different machine than WP is running on) actually writes the updated data to disc? Note: I have complete control over all of the plugin/theme code used on this site, so I can ensure that my save_cpt() func is the only that will fire on edits to this CPT. – Paul 'Sparrow Hawk' Biron Mar 5 '17 at 21:44
  • 1
    I haven't seen any code for asynchronous operation in $wpdb or Wordpress in general. So $wpdb->update() will wait before it gets response from server. The only issue I can think of is DB server response is too late and php execution time expires which means that the cron task do not get fired. But that is a server optimization problem rather than a wordpress one. – sakibmoon Mar 5 '17 at 21:58
  • On the 2nd point: that's probably a good idea. I just hacked up something to use the _edit_lock post_meta that WP core sets when a post is being edited (to simulate that the administrator user has acquired the lock). This kinda-sorta works, but will need some more research/testing to make sure. – Paul 'Sparrow Hawk' Biron Mar 5 '17 at 22:18
  • @Paul'SparrowHawk'Biron There are lots of hook in edit page section. You can use those to take appropriate action based on your need. – sakibmoon Mar 5 '17 at 22:39
  • I just did some poking around into the source for wpdb::_do_query(), which calls PHP: mysqli_query() and,yes, everything does appear to be synchronous. I'll talk to my DBA to make sure there is nothing on the db server-side which could mess this up. – Paul 'Sparrow Hawk' Biron Mar 5 '17 at 23:06

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.