Delay an action until current action is completed

Note that the third input argument for the save_post callback, tells us whether it’s an update or not. That could be helpful here, I think.

Taking your example as is, one suggestion could be:

add_action( 'save_post', function(  $post_ID, $post, $update ) {

   postUpdate( $post_ID );

   if ( $update ) {
       deleteCacheOnCloudfront( $post_ID, $post, $update );
   }

}, 10, 3 );

to run the deleteCacheOnCloudfront() function after the postUpdate() function on post updates only.

The save_post is a very general hook and there exists more specific ones, like save_post_{post_type} or other based on post status transitions, if you want to avoid running your code when .it doesn’t need to.

The postUpdate() function name is very general, so you should consider using a namespace or a function prefix, to avoid possible name collisions.

Hopefully the deleteCacheOnCloudfront() runs quickly (short timeout) and will not let the user wait too long during each post save.

Hope it helps!

Update:

If deleteCacheOnCloudfront() depends on $post_before and $post_after we can consider:

/**
 * Run postUpdate() on save_post with priority 10.
 */
add_action( 'save_post', function(  $post_ID, $post, $update ) {
   postUpdate( $post_ID );
}, 10, 3 );

/**
 * Run deleteCacheOnCloudfront() on save_post with priority 11 when post is updated.
 */
add_action( 'post_updated', function(  $post_ID, $post_before, $post_after ) {
    add_action( 'save_post', 
        function(  $post_ID, $post, $update ) use ( $post_before, $post_after ) {
            deleteCacheOnCloudfront( $post_ID, $post_before, $post_after );
        }, 11, 3 );
}, 10, 3 );

where we pass data from the parent scope with the use keyword and use different priority to make sure deleteCacheOnCloudfront() (priority 11) runs after postUpdate() (priority 10), within the save_post action.

We could also write this as a class instead, to move data across different hooks.