Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog

AsyncGenerator::validate_statusprivateWC 1.0

Validates the status of the feed generation.

Makes sure that the file exists for completed jobs, that scheduled jobs are not stuck, etc.

Method of the class: AsyncGenerator{}

Returns

true|false. True if the status is valid, false otherwise.

Usage

// private - for code of main (parent) class only
$result = $this->validate_status( $status ): bool;
$status(array) (required)
The status of the feed generation.

AsyncGenerator::validate_status() code WC 11.0.0

private function validate_status( array $status ): bool {
	// A failed job is never served as-is. get_status() surfaces the failure to the client once and
	// then clears it, so the client can react and its next poll starts a fresh run; force_regeneration()
	// likewise treats it as invalid and regenerates. Either way it must not validate.
	if ( self::STATE_FAILED === $status['state'] ) {
		return false;
	}

	// For completed jobs, the file must still exist and not be expired (e.g. manually deleted, or a
	// cleanup job that failed to clear an expired feed).
	if ( self::STATE_COMPLETED === $status['state'] ) {
		if ( ! file_exists( $status['path'] ) ) {
			return false;
		}

		if ( ! isset( $status['completed_at'] ) ) {
			return false;
		}

		if ( $status['completed_at'] + self::FEED_EXPIRY < time() ) {
			return false;
		}
	}

	/**
	 * Allows the timeout for a feed to remain in `scheduled` state to be changed. Past this point
	 * Action Scheduler is typically stuck and the job is regenerated.
	 *
	 * @param int $stuck_time The stuck time in seconds.
	 * @return int The stuck time in seconds.
	 * @since 10.5.0
	 */
	$scheduled_timeout = apply_filters( 'woocommerce_product_feed_scheduled_timeout', 10 * MINUTE_IN_SECONDS );
	if (
		self::STATE_SCHEDULED === $status['state']
		&& (
			! isset( $status['scheduled_at'] )
			|| time() - $status['scheduled_at'] > $scheduled_timeout
		)
	) {
		return false;
	}

	// An in-progress job that has not refreshed its heartbeat (`updated_at`, set on start and after
	// every batch) within the timeout was most likely killed (host timeout or out of memory) before
	// it could mark itself failed. Treat it as stuck so a new feed can be generated.
	if ( self::STATE_IN_PROGRESS === $status['state'] ) {
		$last_activity = $status['updated_at'] ?? $status['scheduled_at'] ?? 0;

		/**
		 * Allows the heartbeat timeout for an `in_progress` feed to be changed. Past this point the
		 * job is treated as stuck and regenerated.
		 *
		 * The default is kept comfortably larger than the per-batch time budget on purpose. The
		 * heartbeat only refreshes between batches, so the longest gap a healthy job can produce is
		 * roughly one batch (`woocommerce_product_feed_batch_time_limit`). A timeout at or near that
		 * budget would let a single slow-but-valid batch look stuck, and recovery would then discard
		 * the partial the live process is still writing. Deriving it as a multiple (with a floor)
		 * keeps that margin even when the batch budget is raised via its own filter.
		 *
		 * @param int $stuck_time The stuck time in seconds.
		 * @return int The stuck time in seconds.
		 * @since 11.0.0
		 */
		$in_progress_timeout = apply_filters(
			'woocommerce_product_feed_in_progress_timeout',
			max( 15 * MINUTE_IN_SECONDS, 3 * $this->get_batch_time_limit() )
		);
		if ( time() - $last_activity > $in_progress_timeout ) {
			return false;
		}
	}

	return true;
}