array_intersect_key( $row, array_flip( self::FIELDS ) ); $event = array( sanitize_key( $operation ), $id, $before === null ? null : $snapshot( $before ), $snapshot( $after ) ); if ( BookingLock::is_held() ) { // Caller-owned locks may outlive the handler. No listener runs under that mutex. self::$pending[] = $event; add_action( 'abientot_booking_lock_released', array( self::class, 'flush' ) ); return; } self::emit( $event ); } public static function flush(): void { if ( BookingLock::is_held() ) { return; } $pending = self::$pending; self::$pending = array(); foreach ( $pending as $event ) { self::emit( $event ); } } private static function emit( array $event ): void { try { do_action( 'abientot_booking_committed', ...$event ); } catch ( \Throwable $error ) { /* Persistence succeeded; listeners own durable retries. */ } } /** Request-local notification follows committed event listeners and actual mutex release. */ public static function notify_after_unlock( callable $send ): void { if ( ! BookingLock::is_held() ) { try { $send(); } catch ( \Throwable $error ) { } return; } $callback = null; $callback = static function () use ( &$callback, $send ): void { remove_action( 'abientot_booking_lock_released', $callback, 20 ); try { $send(); } catch ( \Throwable $error ) { } }; add_action( 'abientot_booking_lock_released', $callback, 20 ); } }