0

I have a Wordpress plugin which sends post data after a post/postmeta change occurs.

The problem is that there can be very many postmeta changes on a busy Wordpress site, so I'd like to debounce/throttle/aggregate the meta updates to a single POST call, wrapped in a 1 second period.

Don't know how to approach this one, as I've been using async languages for some time now, and couldn't find a setTimeout equivalent for PHP.
Any shareable ideas?

add_action( 'updated_post_meta', 'a3_updated_post_meta', 10, 4 );

function a3_updated_post_meta($meta_id, $post_id, $meta_key, $meta_value){
    global $wpdb;
    global $a3_types_to_send;

    a3_write_log('---> u p d a t e d  post  m e t a');

    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;

    $mongo_dest_address = 'http://localhost:8080/admin/dirty';
    $reason = 'edit_meta';

    $dirty_post_ids = get_option('a3_dirty_post_ids');

    if(! is_array($dirty_post_ids) ){
        $dirty_post_ids = array();
    }    

    $dirty_post_ids[] = (int) $post_id;

    update_option('a3_dirty_post_ids', array_unique($dirty_post_ids));    

    $object_type = $wpdb->get_var( $wpdb->prepare("select post_type from $wpdb->posts where ID = %d", $post_id) );

    if(in_array($object_type, $a3_types_to_send)){
        a3_send_post_trans($post_id, $reason);  
    }            
}
steakoverflow
  • 1,206
  • 2
  • 15
  • 24

2 Answers2

2

There is no straightforward way to do so in PHP. What I would propose to you is to explore other ideas like:

A) stop firing those actions and running cron script every x seconds (simple php script which is being fired by server in specific interval which would process posts) B) firing actions in similar way as you do it now and putting the posts into a specific queue (it could have any forms depending on your expertise, from simplest ones to for example RabbitMQ). Afterwards you would have to create queueHandler script (in a similar way as in first point) which would process your posts from the queue.

Owi
  • 488
  • 2
  • 7
  • What would be the fastest RabbitMQ scheme for the fire and forget type of publisher? I have implemented the basic scenario but it still seems to add 5-6 seconds for about 20-ish postmeta calls in one request. – steakoverflow Jun 23 '18 at 06:42
  • I think I would have to see it to tell, but are yout alking about the 5-6 of a runtime or it fires AFTER 5-6 seconds? – Owi Jun 23 '18 at 16:31
  • Thanks @Owi, it turns out your idea about Rabbit shaved 5-6s off my request, and this other 5s was related to update_option calls not the RabbitMQ ones, so I'll mark your answer as the solution. – steakoverflow Jun 25 '18 at 05:55
0

This is how I solved this on the save_post hook

    function debounce_send() {
        $send_time = get_transient('send_time');

        if($send_time) {
            wp_clear_scheduled_hook('run_send')
            wp_schedule_single_event($send_time, 'run_send');
            
        } else {
            run_send();
            set_transient('send_time', time() + 60, 60);
        }
    }
    add_action('save_post', 'debounce_send');

I then do this:

    function run_send() {
        // Send an email here
    }
    add_action( 'run_send', 'run_send' );

The result is it will send 1 email AT MOST every 60 seconds.

Drew Baker
  • 14,154
  • 15
  • 58
  • 97