(string) $owner, 'at' => $now, 'exp' => $now + max( 60, (int) $ttl ) ) ); // Atomic insert: fails (returns false) if the row already exists. if ( add_option( $key, $rec, '', 'no' ) ) { return true; } // Row exists — steal it only if the previous holder let it lapse. $cur = json_decode( (string) get_option( $key, '' ), true ); if ( ! is_array( $cur ) || empty( $cur['exp'] ) || (int) $cur['exp'] < $now ) { update_option( $key, $rec, false ); return true; } return false; } /** * Extend a held lock's expiry (call as a job makes progress). * * @param string $name Lock name. * @param int $ttl Seconds to extend from now. * @return void */ public static function touch( $name, $ttl = 900 ) { $key = self::key( $name ); $cur = json_decode( (string) get_option( $key, '' ), true ); if ( ! is_array( $cur ) ) { return; // Not held — don't resurrect a released lock. } $cur['exp'] = time() + max( 60, (int) $ttl ); update_option( $key, wp_json_encode( $cur ), false ); } /** * Release a lock. * * @param string $name Lock name. * @return void */ public static function release( $name ) { delete_option( self::key( $name ) ); } /** * Whether a lock is currently held (and not lapsed). * * @param string $name Lock name. * @return bool */ public static function is_held( $name ) { $cur = json_decode( (string) get_option( self::key( $name ), '' ), true ); return is_array( $cur ) && ! empty( $cur['exp'] ) && (int) $cur['exp'] >= time(); } /** * The current holder record, or null. * * @param string $name Lock name. * @return array|null */ public static function holder( $name ) { $cur = json_decode( (string) get_option( self::key( $name ), '' ), true ); return is_array( $cur ) ? $cur : null; } }