Skip to content

feat(clouddevice): add opt-in retry for transient socket drops - #1792

Draft
naseemkullah wants to merge 3 commits into
Adyen:mainfrom
naseemkullah:feat/http-client-transient-retries
Draft

naseemkullah wants to merge 3 commits into
Adyen:mainfrom
naseemkullah:feat/http-client-transient-retries

Conversation

@naseemkullah

@naseemkullah naseemkullah commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Allow CloudDeviceApi and EncryptedCloudDeviceApi requests to recover from
transient Node.js keep-alive socket drops (socket hang up / ECONNRESET).

  • Add retries?: number to IRequest.Options, defaulting to 0 and capped at 3.
  • Extend ApiException to expose the underlying transport code, such as
    ECONNRESET.
  • Serialize and encrypt Nexo payloads once before retrying so exact payload
    identity (ServiceID, POIID, SaleID, and encrypted NexoBlob) is preserved.
  • Restrict retries to recognized transport socket errors; HTTP 4xx/5xx responses
    and Nexo business errors are not retried.
  • Add Cloud Device API tests verifying identical payload retransmission.

@naseemkullah
naseemkullah requested a review from a team as a code owner September 25, 2026 01:03

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a retry mechanism to HttpURLConnectionClient for handling retryable network errors on idempotent HTTP methods or requests containing an idempotency key, complete with comprehensive unit tests. The feedback suggests registering a no-op error listener during request cleanup to prevent unhandled process crashes, using optional chaining on error.message to avoid potential TypeErrors, and utilizing the built-in getHeader method for a more efficient and readable idempotency key lookup.

Comment thread src/httpClient/httpURLConnectionClient.ts Outdated
Comment thread src/httpClient/httpURLConnectionClient.ts Outdated
Comment thread src/httpClient/httpURLConnectionClient.ts Outdated
@naseemkullah
naseemkullah force-pushed the feat/http-client-transient-retries branch 3 times, most recently from d67865d to 34a0dbf Compare September 25, 2026 01:32
Add configurable network-level retries to `HttpURLConnectionClient` for transient
connection failures from stale pooled keep-alive sockets, including `socket hang up`,
`ECONNRESET`, `EPIPE`, and `ETIMEDOUT`.

- Add `maxRetries` to `HttpURLConnectionClientOptions`, defaulting to `0` and capped
    at `3` to bound latency and prevent unbounded retry loops.
- Retry only before the `ClientRequest` emits its `response` event.
- Retry `GET`, `HEAD`, `OPTIONS`, `PUT`, and `DELETE` requests according to HTTP
    idempotency semantics.
- Require a non-empty `Idempotency-Key` for `POST` and `PATCH` retries.
- Preserve request bodies, headers, and idempotency keys across retries and `308`
    redirects.
- Abort failed `ClientRequest` instances without destroying the shared HTTPS agent,
    avoiding disruption to concurrent requests.
- Re-export `HttpURLConnectionClientOptions` from the package entry point.
- Add coverage for response-boundary safety, idempotency policy, retry exhaustion,
    and the retry cap.
@naseemkullah
naseemkullah force-pushed the feat/http-client-transient-retries branch from 34a0dbf to 8ec38e8 Compare September 25, 2026 01:36
@gcatanese

Copy link
Copy Markdown
Contributor

Hey @naseemkullah, still having issues with the connection? Which kind of problem are you experiencing?

@naseemkullah

Copy link
Copy Markdown
Contributor Author

Hey @naseemkullah, still having issues with the connection? Which kind of problem are you experiencing?

Hey @gcatanese, since enabling keepalive, we've seen a decrease in ECONNRESETs, but a significant uptick in socket hang up errors. These occur when an idle pooled connection is reused right as Adyen closes it.

@gcatanese

Copy link
Copy Markdown
Contributor

Hey @naseemkullah, still having issues with the connection? Which kind of problem are you experiencing?

Hey @gcatanese, since enabling keepalive, we've seen a decrease in ECONNRESETs, but a significant uptick in socket hang up errors. These occur when an idle pooled connection is reused right as Adyen closes it.

The team is reviewing this, my question is if this PR addresses the problem? Are you able to confirm that?
If possible, it would be great if you can package the library, including your changes, and use it with your integration until you can confirm this. Then we can plan a release.

Unfortunately we are not able to release alpha/beta versions, which would really help us to validate these types of bug fixes, but we are considering it for the future.

@naseemkullah
naseemkullah marked this pull request as draft September 25, 2026 13:30
@naseemkullah
naseemkullah marked this pull request as ready for review September 25, 2026 13:54
@naseemkullah
naseemkullah marked this pull request as draft September 25, 2026 13:55
Allow CloudDeviceApi and EncryptedCloudDeviceApi requests to recover from
transient Node.js keep-alive socket drops (`socket hang up` / `ECONNRESET`).

- Add `retries?: number` to `IRequest.Options`, defaulting to 0 and capped at 3.
- Extend `ApiException` to expose the underlying transport code, such as
  `ECONNRESET`.
- Serialize and encrypt Nexo payloads once before retrying so exact payload
  identity (`ServiceID`, `POIID`, `SaleID`, and encrypted `NexoBlob`) is preserved.
- Restrict retries to recognized transport socket errors; HTTP 4xx/5xx responses
  and Nexo business errors are not retried.
- Add Cloud Device API tests verifying identical payload retransmission.
@naseemkullah naseemkullah changed the title feat(httpClient): add transient network error retry support feat(clouddevice): add opt-in retry for transient socket drops Sep 25, 2026
@naseemkullah

Copy link
Copy Markdown
Contributor Author

Hey @naseemkullah, still having issues with the connection? Which kind of problem are you experiencing?

Hey @gcatanese, since enabling keepalive, we've seen a decrease in ECONNRESETs, but a significant uptick in socket hang up errors. These occur when an idle pooled connection is reused right as Adyen closes it.

The team is reviewing this, my question is if this PR addresses the problem? Are you able to confirm that? If possible, it would be great if you can package the library, including your changes, and use it with your integration until you can confirm this. Then we can plan a release.

Unfortunately we are not able to release alpha/beta versions, which would really help us to validate these types of bug fixes, but we are considering it for the future.

Good call @gcatanese as I implemented an app side retry (which is working great btw!) I realized the Nexo protocol has no idempotency key header. I completely revamped this PR. Could re-request Gemini to review since its a different approach, or I can open a new one, let me know. Thanks!

This branch has not been deployed

No deployments
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.

2 participants