Skip to content

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

Merged
ksvirkou-hubspot merged 2 commits into
HubSpot:masterfrom
AScriver:master
May 11, 2026
Merged

Add retry middleware support for transient cURL connection errors (52/55/56)#614
ksvirkou-hubspot merged 2 commits into
HubSpot:masterfrom
AScriver:master

Conversation

@AScriver
Copy link
Copy Markdown
Contributor

@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
Contributor 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.

@ksvirkou-hubspot ksvirkou-hubspot merged commit 7a14c0a into HubSpot:master May 11, 2026
2 checks passed
@ksvirkou-hubspot
Copy link
Copy Markdown
Collaborator

Thanks for the contribution!

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