Automattic\WooCommerce\Internal\BatchProcessing

BatchProcessingController::mutate_enqueued_processorsprivateWC 11.0.0

Run a read-modify-write of the enqueued-processors option inside a short-lived critical section.

The list is stored in a single option and mutated by several code paths (including the per-request 'shutdown' enqueue from continuous HPOS background sync), so an unguarded read-modify-write can lose updates under concurrency: two requests read the same list, each writes its own version, and the later write silently drops the other's change. This serializes those mutations with a self-expiring options-table mutex and re-reads the freshest persisted value inside the lock so the mutator always operates on current state.

The lock is best-effort: if it cannot be acquired within ENQUEUED_PROCESSORS_LOCK_ATTEMPTS tries the mutation still proceeds, which is no worse than the previous lock-free behavior. The fresh re-read inside the section narrows the race window even when the lock provides no real exclusion, and the watchdog reconciles any residual divergence on its next run.

Метод класса: BatchProcessingController{}

Хуков нет.

Возвращает

array. The list as persisted (the mutator's return value).

Использование

// private - только в коде основоного (родительского) класса
$result = $this->mutate_enqueued_processors( $mutator ): array;
$mutator(callable) (обязательный)
Receives the current list (array of class-name strings) and returns the new list.

Список изменений

С версии 11.0.0 Введена.

Код BatchProcessingController::mutate_enqueued_processors() WC 11.1.1

private function mutate_enqueued_processors( callable $mutator ): array {
	$lock_token = $this->acquire_enqueued_processors_lock();
	try {
		/*
		 * Drop any request-cached copy so the read below reflects writes committed by concurrent requests
		 * that landed after this request first read the option. Both the per-option entry AND the shared
		 * 'notoptions' entry must be cleared: when the option does not yet exist (first enqueue, or after a
		 * corrupted option was deleted), get_option() short-circuits on a stale 'notoptions' hit and would
		 * otherwise return the default empty list even though a concurrent request just created the row.
		 */
		wp_cache_delete( self::ENQUEUED_PROCESSORS_OPTION_NAME, 'options' );
		wp_cache_delete( 'notoptions', 'options' );
		$current = $this->get_enqueued_processors();
		$updated = $mutator( $current );
		if ( $updated !== $current ) {
			$this->set_enqueued_processors( $updated );
		}
		return $updated;
	} finally {
		if ( null !== $lock_token ) {
			$this->release_enqueued_processors_lock( $lock_token );
		}
	}
}