Skip to content

Add retry middleware support for transient cURL connection errors (52/55/56)#614

Open
AScriver wants to merge 2 commits intoHubSpot:masterfrom
AScriver:master
Open

Add retry middleware support for transient cURL connection errors (52/55/56)#614
AScriver wants to merge 2 commits intoHubSpot:masterfrom
AScriver:master

Conversation

@AScriver
Copy link
Copy Markdown

@AScriver AScriver commented May 4, 2026

Fixes #597.

Adds opt-in retry support for transient transport-level cURL failures that currently bypass HTTP-status retry middleware.

Changes

  • Add createConnectionErrorsMiddleware(...)
  • Add getRetryFunctionByConnectionErrors(...)
  • Default retriable cURL error codes: 52, 55, 56
  • Add unit tests for:
    • retriable errno/message cases
    • non-retriable case
    • max-retry cutoff
  • Update README retry example to include connection-error middleware

@ksvirkou-hubspot
Copy link
Copy Markdown
Collaborator

I noticed 4 test failures in the CI run. Could you please fix them?

@ksvirkou-hubspot
Copy link
Copy Markdown
Collaborator

Would it make sense to add a default delay function here?
Retrying transient cURL connection errors immediately might be a bit aggressive, so an exponential backoff could be a safer default.
For example:

$delayFunction = function (int $retries): int {
    return min(1000 * (2 ** $retries), 10000);
};

@AScriver
Copy link
Copy Markdown
Author

AScriver commented May 8, 2026

Would it make sense to add a default delay function here? Retrying transient cURL connection errors immediately might be a bit aggressive, so an exponential backoff could be a safer default. For example:

$delayFunction = function (int $retries): int {
    return min(1000 * (2 ** $retries), 10000);
};

I checked this, and Guzzle already applies an exponential backoff when the delay function is null.

createConnectionErrorsMiddleware() passes $delayFunction through to Middleware::retry(). Guzzle's RetryMiddleware constructor then defaults a missing delay to RetryMiddleware::exponentialDelay, which returns 2 ** ($retries - 1) * 1000 milliseconds.

So the default sequence is already 1000ms, 2000ms, 4000ms, etc. I think leaving this delegated to Guzzle is preferable here because adding our own default would duplicate existing behavior and could subtly diverge over time.

That said, I'm open to making the default explicit here as well if that's preferred.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cURL errors in contact search via email

2 participants