0 && ( time() - $held_since ) > $ttl ) { global $wpdb; // phpcs:disable WordPress.DB.DirectDatabaseQuery -- lock row: must bypass the options API and its cache. $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name = %s AND option_value = %s", $key, (string) $held_since ) ); // phpcs:enable WordPress.DB.DirectDatabaseQuery self::forget_cache( $key ); if ( $deleted ) { return self::claim( $key ); } } return false; } public static function release( string $key ): void { delete_option( $key ); } /** * Run $work under a lock, waiting a moment for it. When the lock cannot be had the work runs * anyway: it is used for history lines, where a rare lost line beats a lost event. * * @return mixed What $work returned. */ public static function run( string $key, callable $work, int $ttl = 10, int $wait_ms = 2000 ): mixed { $locked = false; $waited = 0; while ( ! ( $locked = self::acquire( $key, $ttl ) ) && $waited < $wait_ms ) { usleep( 50000 ); $waited += 50; } try { return $work(); } finally { if ( $locked ) { self::release( $key ); } } } private static function claim( string $key ): bool { global $wpdb; // A duplicate key is the expected outcome, not an error to print or log. $suppressed = $wpdb->suppress_errors( true ); // phpcs:disable WordPress.DB.DirectDatabaseQuery -- lock row: a plain INSERT the unique key refuses; add_option() would overwrite. $inserted = $wpdb->query( $wpdb->prepare( "INSERT INTO {$wpdb->options} (option_name, option_value, autoload) VALUES (%s, %s, %s)", $key, (string) time(), 'off' ) ); // phpcs:enable WordPress.DB.DirectDatabaseQuery $wpdb->suppress_errors( $suppressed ); if ( 1 !== (int) $inserted ) { return false; } self::forget_cache( $key ); return true; } private static function held_since( string $key ): int { global $wpdb; // phpcs:disable WordPress.DB.DirectDatabaseQuery -- lock row: read from the table, not the options cache. return (int) $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s", $key ) ); // phpcs:enable WordPress.DB.DirectDatabaseQuery } private static function forget_cache( string $key ): void { wp_cache_delete( $key, 'options' ); wp_cache_delete( 'notoptions', 'options' ); } }