VOOZH about

URL: https://deepwiki.com/friendsofhyperf/components/4.3-retry-logic-and-error-handling

⇱ Retry Logic and Error Handling | friendsofhyperf/components | DeepWiki


Loading...
Last indexed: 14 February 2026 (15d5ca)
Menu

Retry Logic and Error Handling

This document covers the HTTP client's automatic retry mechanisms and error handling capabilities. The retry system provides configurable attempts with delays and conditional logic, while the error handling system offers multiple ways to throw exceptions based on response status codes.

For information about request building and execution, see Request Building and Execution. For testing error scenarios with fakes, see Testing with Fakes and Assertions.

Overview

The HTTP client implements retry logic within the PendingRequest class, using the retry() helper function from the Support library to execute requests multiple times on failure. Error handling is split between response evaluation methods on the Response class and exception throwing configuration on the PendingRequest class.

Sources: src/http-client/src/PendingRequest.php145-175 src/http-client/src/Response.php227-251

Retry Configuration

Retry Method Parameters

The retry() method on PendingRequest configures retry behavior with four parameters:

ParameterTypeDefaultDescription
$timesint|array1Number of attempts or array of backoff delays
$sleepMillisecondsClosure|int0Fixed delay or callback returning delay
$whencallable|nullnullCallback to determine if retry should occur
$throwbooltrueWhether to throw exception after all retries fail

Sources: src/http-client/src/PendingRequest.php610-622

Configuration Properties

The retry configuration is stored in several protected properties:

  • $tries (int): Total number of attempts, defaults to 1
  • $backoff (array|null): Array of millisecond delays for exponential backoff
  • $retryDelay (Closure|int|null): Delay between retries in milliseconds
  • $retryThrow (bool): Whether to throw exception when all retries exhausted
  • $retryWhenCallback (callable|null): Callback receiving exception/response and PendingRequest

When an array is passed to $times, it's stored in $backoff and the $tries count is set to count($backoff) + 1.

Sources: src/http-client/src/PendingRequest.php145-175 src/http-client/src/PendingRequest.php612-620


Diagram: Retry Configuration Flow

Sources: src/http-client/src/PendingRequest.php610-622

Retry Execution Flow

Main Retry Loop

The retry logic executes within the send() method using the FriendsOfHyperf\Support\retry() helper function. The implementation wraps request execution in a retry closure that handles both successful and failed responses.

Sources: src/http-client/src/PendingRequest.php878-924


Diagram: Retry Execution Sequence

Sources: src/http-client/src/PendingRequest.php878-924

Retry Decision Logic

The decision to retry involves multiple conditions evaluated in sequence:

  1. Response Status Check: !$response->successful() (status not 2xx)
  2. Retry When Callback: If retryWhenCallback is set, it's invoked with the exception/response and must return true
  3. Attempt Count: Current attempt must be less than configured tries
  4. Exception Throwing: After all retries, exceptions are thrown based on throwCallback and retryThrow settings

Sources: src/http-client/src/PendingRequest.php880-911

Retry Delay Calculation

The delay between retries is determined by:

  • Backoff Array: If provided, uses $backoff[$attempt - 1] for each attempt
  • Retry Delay: Uses retryDelay value (int) or invokes it as closure with ($attempt, $exception)
  • Default: Falls back to 100 milliseconds

The actual delay execution is handled by the retry() helper function, which calls Sleep::usleep() with the microsecond value.

Sources: src/http-client/src/PendingRequest.php878-924 src/http-client/src/PendingRequest.php161

Error Detection and Classification

Response Status Evaluation

The Response class provides several methods to classify HTTP response statuses:

MethodStatus RangeDescription
successful()200-299Request succeeded
redirect()300-399Redirect response
failed()400-599Client or server error
clientError()400-499Client-side error (bad request, unauthorized, etc.)
serverError()500-599Server-side error (internal error, bad gateway, etc.)

Additionally, specific status code methods exist:

  • ok() - Status 200
  • created() - Status 201
  • accepted() - Status 202
  • noContent() - Status 204
  • movedPermanently() - Status 301
  • found() - Status 302
  • badRequest() - Status 400
  • unauthorized() - Status 401
  • forbidden() - Status 403
  • notFound() - Status 404
  • unprocessableEntity() - Status 422
  • tooManyRequests() - Status 429

Sources: src/http-client/src/Response.php205-251 src/http-client/src/Concerns/DeterminesStatusCode.php


Diagram: Response Status Classification

Sources: src/http-client/src/Response.php205-251 src/http-client/src/Concerns/DeterminesStatusCode.php

Exception Types

The HTTP client throws two exception types:

  1. RequestException: Thrown for HTTP-level errors (4xx, 5xx status codes)

  2. ConnectionException: Thrown for connection-level failures

Sources: src/http-client/src/RequestException.php1-48 src/http-client/src/ConnectionException.php

Exception Throwing Mechanisms

Basic Exception Throwing

The throw() method on PendingRequest configures automatic exception throwing on errors:


When configured, the $throwCallback is stored and invoked if a response fails. The callback receives the Response and RequestException:


Sources: src/http-client/src/PendingRequest.php691-696

Conditional Throwing (throwIf/throwUnless)

The throwIf() method accepts either a boolean or callable condition:

  • Boolean Condition: If true, sets throw callback and returns $this
  • Callable Condition: Stores as $throwIfCallback, evaluated before throwing

The throwUnless() method is the inverse, calling throwIf(!$condition).

During retry execution, the throw check evaluates:


Sources: src/http-client/src/PendingRequest.php704-722 src/http-client/src/PendingRequest.php894-898

Response-Level Throwing

The Response class provides immediate throwing methods:

  • throw(?callable $callback = null): Throws RequestException if response failed
  • throwIf($condition): Throws if condition evaluates to true
  • throwIfStatus($statusCode): Throws if status matches (int or callable)
  • throwUnlessStatus($statusCode): Throws unless status matches
  • throwIfClientError(): Throws if 4xx status
  • throwIfServerError(): Throws if 5xx status

These methods can be chained after receiving the response:


Sources: src/http-client/src/Response.php327-412


Diagram: Exception Throwing Mechanisms

Sources: src/http-client/src/PendingRequest.php691-722 src/http-client/src/Response.php327-412 src/http-client/src/PendingRequest.php894-898

Connection Error Handling

ConnectException Handling

Connection-level failures are caught separately from HTTP response errors. When Guzzle throws a ConnectException, the HTTP client:

  1. Dispatches a ConnectionFailed event with the Request
  2. Wraps the exception in a ConnectionException
  3. Allows the retry mechanism to catch and retry it

The handling occurs at src/http-client/src/PendingRequest.php913-917:


The retry() helper's when-closure evaluates connection exceptions through the retryWhenCallback if provided, or defaults to retrying all exceptions.

Sources: src/http-client/src/PendingRequest.php913-917 src/http-client/src/PendingRequest.php918-924

Async Request Error Handling

For asynchronous requests (when async() is called), error handling follows a different path through promise chains:

  1. The makePromise() method returns a promise instead of executing synchronously
  2. The otherwise() handler catches ConnectException and RequestException
  3. For connection errors, it dispatches ConnectionFailed and wraps in ConnectionException
  4. The handlePromiseResponse() method evaluates retry conditions
  5. If retries remain and retryWhenCallback returns true, creates a new promise with incremented attempt

Sources: src/http-client/src/PendingRequest.php1260-1334

Advanced Retry Scenarios

Exponential Backoff with Array

Passing an array to retry() configures exponential backoff with specific delays:


This attempts the request 4 times total (1 initial + 3 retries) with delays of 100ms, 200ms, and 400ms between attempts.

Sources: src/http-client/src/PendingRequest.php612-615

Dynamic Delay Calculation

The $sleepMilliseconds parameter accepts a closure for dynamic delay calculation:


The closure receives the current attempt number and the exception that triggered the retry.

Sources: src/http-client/src/PendingRequest.php610

Selective Retry with When Callback

The $when callback provides fine-grained control over retry decisions:


The callback receives either a RequestException (for HTTP errors) or ConnectionException (for network errors), plus the PendingRequest instance.

Sources: src/http-client/src/PendingRequest.php887-892 src/http-client/src/PendingRequest.php918-924

Retry Without Throwing

Setting $throw to false prevents exception throwing after all retries are exhausted:


This allows the caller to handle failures programmatically by checking $response->failed().

Sources: src/http-client/src/PendingRequest.php168 src/http-client/src/PendingRequest.php908-910

Error Handling in Test Scenarios

Faking Failed Responses

The testing system supports faking failed responses to verify error handling:


When faking responses, the status code determines whether failed(), clientError(), or serverError() return true.

Sources: tests/HttpClient/HttpClientTest.php

Testing Retry Behavior

Retry logic can be verified using response sequences:


The fake system tracks each request, allowing verification that retries occurred.

Sources: tests/HttpClient/HttpClientTest.php

Summary

The HTTP client's retry and error handling system provides:

  • Configurable Retry Logic: Fixed attempts, exponential backoff, or custom delays
  • Conditional Retries: Callbacks to selectively retry based on error type
  • Multiple Throwing Modes: Configure throwing on PendingRequest or Response
  • Status Classification: Rich set of methods to evaluate response success
  • Connection Handling: Separate path for network-level failures
  • Test Support: Full faking and sequence support for error scenarios

The retry mechanism integrates with the FriendsOfHyperf\Support\retry() helper, providing consistent retry behavior across the framework. All retry decisions can be customized through the retryWhenCallback, enabling sophisticated error handling strategies like circuit breakers or selective retry policies.

Sources: src/http-client/src/PendingRequest.php src/http-client/src/Response.php