Skip to content

Drop retry strategy and up cache time #461

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/concepts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ When a request to your site renders one or more remote data blocks, our plugin w

The plugin offers a caching layer for optimal performance and helps avoid rate limiting from remote data sources. It will be used if your WordPress environment configures a [persistent object cache](https://developer.wordpress.org/reference/classes/wp_object_cache/#persistent-cache-plugins). Otherwise, the plugin will utilize in-memory (per-page-load) caching. Deploying to production without a persistent object cache is not recommended.

The default TTL for all cache objects is 60 seconds, but it can be [configured per query or request](../extending/query.md#get_cache_ttl).
The default TTL for all cache objects is 5 minutes, but it can be [configured per query or request](../extending/query.md#get_cache_ttl).

## Theming

Expand Down
27 changes: 0 additions & 27 deletions docs/extending/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,30 +146,3 @@ function custom_query_response_metadata( array $metadata, HttpQueryInterface $qu
}
add_filter( 'remote_data_blocks_query_response_metadata', 'custom_query_response_metadata', 10, 3 );
```

### remote_data_blocks_http_client_retry_delay

Filter to change the defualt 1 second delapy after an HTTP request fails. The Remote Data Blocks Plugin uses the [Guzzle](https://github.com/guzzle/guzzle) HTTP client. You can read about the response interface in their [documentation](https://docs.guzzlephp.org/en/stable/).

```php
function custom_response_retry_delay( int $retry_after_ms, int $retries, ?ResponseInterface $response ): int {
// Implement a custom exponential backoff strategy.
return floor( pow( 1.5, $retries ) * 1000 );
}
add_filter( 'remote_data_blocks_http_client_retry_delay', 'custom_response_retry_delay', 10, 3 );
```

### remote_data_blocks_http_client_retry_decider

Filter the default HTTP retry logic when an HTTP request fails or encounters an exception. The Remote Data Blocks Plugin uses the [Guzzle](https://github.com/guzzle/guzzle) HTTP client. You can read about the request, response, and exception interfaces in their [documentation](https://docs.guzzlephp.org/en/stable/).

```php
function custom_retry_decider( bool $should_retry, int $retries, RequestInterface $request, ?ResponseInterface $response, ?Exception $exception ): bool {
// Retry on a 408 error if the number of retries is less than 5.
if ( $retries < 5 && $response && 408 === $response->getStatusCode ) {
return true;
}
return $should_retry;
}
add_filter( 'remote_data_blocks_http_client_retry_decider', 'custom_response_retry_on_exception', 10, 5 );
```
60 changes: 0 additions & 60 deletions inc/HttpClient/HttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

namespace RemoteDataBlocks\HttpClient;

use Exception;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\MessageFormatter;
use GuzzleHttp\Middleware;
use GuzzleHttp\Promise\Utils;
Expand All @@ -21,8 +19,6 @@
class HttpClient {
public Client $client;

private const MAX_RETRIES = 3;

public const CACHE_TTL_CLIENT_OPTION_KEY = '__default_cache_ttl';

private string $base_uri;
Expand Down Expand Up @@ -79,11 +75,6 @@ public function init( string $base_uri, array $headers = [], array $client_optio

$this->handler_stack = HandlerStack::create( $request_handler );

$this->handler_stack->push( Middleware::retry(
self::class . '::retry_decider',
self::class . '::retry_delay'
) );

$this->handler_stack->push( Middleware::mapRequest( function ( RequestInterface $request ) {
foreach ( $this->headers as $header => $value ) {
$request = $request->withHeader( $header, $value );
Expand All @@ -107,57 +98,6 @@ public function init( string $base_uri, array $headers = [], array $client_optio
] ) );
}

/**
* Determine if the request request be retried.
*
* @param int $retries Number of retries that have been attempted so far.
* @param RequestInterface $request Request that was sent.
* @param ResponseInterface $response Response that was received.
* @param Exception $exception Exception that was received (if any).
* @return bool Whether the request should be retried.
*/
public static function retry_decider( int $retries, RequestInterface $request, ?ResponseInterface $response = null, ?Exception $exception = null ): bool {
// Exceeding max retries is not overrideable.
if ( $retries >= self::MAX_RETRIES ) {
return false;
}

$should_retry = false;

if ( $response && $response->getStatusCode() >= 500 ) {
$should_retry = true;
}

if ( $exception ) {
$should_retry = $should_retry || $exception instanceof ConnectException;
}

return apply_filters( 'remote_data_blocks_http_client_retry_decider', $should_retry, $retries, $request, $response, $exception );
}

/**
* Calculate the delay before retrying a request.
*
* @param int $retries Number of retries that have been attempted so far.
* @param ResponseInterface $response Response that was received.
* @return int Number of milliseconds to delay.
*/
public static function retry_delay( int $retries, ?ResponseInterface $response ): int {
// Be default, implement a linear backoff strategy.
$retry_after = $retries;

if ( $response instanceof ResponseInterface && $response->hasHeader( 'Retry-After' ) ) {
$retry_after = $response->getHeaderLine( 'Retry-After' );

if ( ! is_numeric( $retry_after ) ) {
$retry_after = ( new \DateTime( $retry_after ) )->getTimestamp() - time();
}
}

$retry_after_ms = (int) $retry_after * 1000;
return apply_filters( 'remote_data_blocks_http_client_retry_delay', $retry_after_ms, $retries, $response );
}

/**
* Queue a request for later execution.
*/
Expand Down
2 changes: 1 addition & 1 deletion inc/HttpClient/RdbCacheStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

class RdbCacheStrategy extends GreedyCacheStrategy {
private const CACHE_INVALIDATING_REQUEST_HEADERS = [ 'Authorization', 'Cache-Control' ];
private const FALLBACK_CACHE_TTL_IN_SECONDS = 60;
private const FALLBACK_CACHE_TTL_IN_SECONDS = 300; // 5 minutes
private const WP_OBJECT_CACHE_GROUP = 'remote-data-blocks';

private Logger $logger;
Expand Down
34 changes: 0 additions & 34 deletions tests/inc/HttpClient/HttpClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,40 +60,6 @@ public function testPost(): void {
$this->assertSame( 'MISS', $response->getHeaderLine( RdbCacheMiddleware::HEADER_CACHE_INFO ) );
}

public function testRetryDecider(): void {
$request = new Request( 'GET', '/test' );

// Test max retries
$this->assertFalse( HttpClient::retry_decider( 3, $request ) );

// Test 500 status code
$response = new Response( 500 );
$this->assertTrue( HttpClient::retry_decider( 0, $request, $response ) );

// Test ConnectException
$exception = new ConnectException( 'Error Connecting', $request );
$this->assertTrue( HttpClient::retry_decider( 0, $request, null, $exception ) );

// Test no retry on good response
$response = new Response( 200 );
$this->assertFalse( HttpClient::retry_decider( 0, $request, $response ) );
}

public function testRetryDelay(): void {
$response = new Response( 429, [ 'Retry-After' => '120' ] );
$delay = HttpClient::retry_delay( 1, $response );
$this->assertSame( 120000, $delay );

$response = new Response( 429, [ 'Retry-After' => ( new \DateTime( '+2 minutes' ) )->format( \DateTime::RFC7231 ) ] );
$delay = HttpClient::retry_delay( 1, $response );
$this->assertGreaterThan( 119000, $delay );
$this->assertLessThan( 121000, $delay );

$response = new Response( 500 );
$delay = HttpClient::retry_delay( 2, $response );
$this->assertSame( 2000, $delay );
}

public function testQueueRequestAndExecuteParallel(): void {
$this->mock_handler->append( new Response( 200, [], 'Response 1' ) );
$this->mock_handler->append( new Response( 201, [], 'Response 2' ) );
Expand Down
Loading