-
Notifications
You must be signed in to change notification settings - Fork 750
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
Intermittent Error: write EPIPE when running stripe client in AWS Lambda #1040
Comments
We've seen this before with AWS Lambda and believe it's an issue/configuration setting on their end. Using When you hear back from AWS would you mind updating this issue with your findings? |
Yea I have aws premium subscription should have a response soon. I did find similar issues that people reported here with other libs:
So my latest theory is it's something related to keep-alive and sockets expiring, but at this point I added the retry and waiting for AWS to respond back to me. |
Hi @paulasjes-stripe - here's the response we got from AWS:
So I'll just use Stripe's retry logic for now, as I don't seem to have control over stripes background processes. Is it the keep alive connection that is causing this issue? Not sure. Our lambda is very simple, it basically just returns the results from this line:
It's a 2048mb lambda running nodejs 12. It is called via a GraphQL function transfomer (https://docs.amplify.aws/cli/function), but I don't think those details matter much. Interestingly, I have other lambdas that also call the above rest API, but have other network calls and involved logic, and I've never ran into the EPIPE issue with them before. |
Thanks @hisham! We're going to look into this to see if there's anything that can be done from our end, but it looks like |
Great. Yes maxNetworkRetries does the job. AWS seems to agree with me that calling destroy method on the httpagent before the lambda exists will probably also resolve this issue:
|
@hisham Do you happen to know if I can wrap my stripe method calls inside trycatch, if I want to use maxNetworkRetries? |
@huntedman we are using maxNetworkRetries and are not wrapping calls around try catch. Stripe seems to handle this stuff internally. |
Hi @hisham sorry for the radio silence about this recently but I'm checking in with a quick update. The response from AWS was very helpful to us (thank you!) and we're actively investigating this issue to provide a better fix than our suggested workaround. When we know more we'll definitely update you here again via this open issue. Thank you for your patience! |
I've spent some time experimenting with AWS lambda, and have a better understanding of these errors. They are happening due to the interaction between
In case you're not familiar, The problem arises when Lambda freezes your Node process. While the process is frozen, the TCP connections can't ping the server to remain active, and the server closes them. When Lambda unfreezes your process, Node isn't aware that the connections have been closed, and it attempts to re-use them. As soon as it does, it gets EPIPE or ECONNRESET. One option for eliminating these errors would be to disable keep-alive when you initialize stripe-node. const https = require('https')
const stripe = require('stripe')('sk_live_xyz', {httpAgent: new https.Agent({keepAlive: false})}) This does mean sacrificing the benefits of keep-alive, but I expect that's an acceptable trade-off especially for low-traffic lambdas. Another possibility would be initializing a new Stripe client with its own keep-alive-enabled agent inside the Lambda handler. This is roughly equivalent to Amazon's suggestion of calling From my perspective, handling these errors by retrying is likely the proper approach, and shouldn't necessarily be viewed as a workaround, or masking an underlying issue, because it is expected/unavoidable that these broken connections will come to exist, and there doesn't seem to be an obvious way of asking Node "how long has it been since the last keep-alive probe on this connection" besides writing to the connection and triggering the error. At the same time, I think we should look into the possibility of making stripe-node handle errors like this by default/more transparently, so that users don't have to configure the retries themselves. That seems to be what Amazon started doing for errors like this for their own SDKs about a month ago (thank you @hisham for linking to that issue, by the way). Anyway I hope this clarifies things and we'll keep you posted. |
Thank you for opening this thread! I had the same issue on a very low traffic site (side project). I used Stripe's Node library inside Netlify functions, and got 502 errors with error message I moved forward with the fix you recommended @richardm-stripe, but the syntax didn't work. The below worked though:
|
Thanks @theoBLT, I've corrected the syntax in the original comment. |
Requests that fail with closed connection errors (ECONNRESET, EPIPE) are automatically retried. - `ECONNRESET` (Connection reset by peer): A connection was forcibly closed by a peer.closed by a peer. This normally results from a loss of the connection on the remote socket due to a timeout or reboot. Commonly encountered via the http and net modules. - `EPIPE` (Broken pipe): A write on a pipe, socket, or FIFO for which there is no process to read the data. Commonly encountered at the net and http layers, indicative that the remote side of the stream being written to has been closed. Fixes: stripe#1040
Requests that fail with closed connection errors (ECONNRESET, EPIPE) are automatically retried. - `ECONNRESET` (Connection reset by peer): A connection was forcibly closed by a peer.closed by a peer. This normally results from a loss of the connection on the remote socket due to a timeout or reboot. Commonly encountered via the http and net modules. - `EPIPE` (Broken pipe): A write on a pipe, socket, or FIFO for which there is no process to read the data. Commonly encountered at the net and http layers, indicative that the remote side of the stream being written to has been closed. Fixes: stripe#1040
Requests that fail with closed connection errors (ECONNRESET, EPIPE) are automatically retried. - `ECONNRESET` (Connection reset by peer): A connection was forcibly closed by a peer.closed by a peer. This normally results from a loss of the connection on the remote socket due to a timeout or reboot. Commonly encountered via the http and net modules. - `EPIPE` (Broken pipe): A write on a pipe, socket, or FIFO for which there is no process to read the data. Commonly encountered at the net and http layers, indicative that the remote side of the stream being written to has been closed. Fixes: stripe#1040
* feat(http-client): Retry requests that failed with closed connection Requests that fail with closed connection errors (ECONNRESET, EPIPE) are automatically retried. - `ECONNRESET` (Connection reset by peer): A connection was forcibly closed by a peer.closed by a peer. This normally results from a loss of the connection on the remote socket due to a timeout or reboot. Commonly encountered via the http and net modules. - `EPIPE` (Broken pipe): A write on a pipe, socket, or FIFO for which there is no process to read the data. Commonly encountered at the net and http layers, indicative that the remote side of the stream being written to has been closed. Fixes: #1040
Oof, #1336 claimed to fix this, so it auto-closed, but I disagree that it's entirely fixed until retries are enabled by default. |
* API Updates (#1413) * Bump version to 8.221.0 * API Updates (#1414) * Bump version to 8.222.0 * API Updates (#1415) * feat(http-client): retry closed connection errors (#1336) * feat(http-client): Retry requests that failed with closed connection Requests that fail with closed connection errors (ECONNRESET, EPIPE) are automatically retried. - `ECONNRESET` (Connection reset by peer): A connection was forcibly closed by a peer.closed by a peer. This normally results from a loss of the connection on the remote socket due to a timeout or reboot. Commonly encountered via the http and net modules. - `EPIPE` (Broken pipe): A write on a pipe, socket, or FIFO for which there is no process to read the data. Commonly encountered at the net and http layers, indicative that the remote side of the stream being written to has been closed. Fixes: #1040 * Remove deprecated orders-related events (#1417) * Bump version to 9.0.0 * API Updates (#1420) * Codegen for openapi 7789931 * Bump version to 9.1.0 * API Updates (#1422) * Codegen for openapi 056745c Co-authored-by: Richard Marmorstein <richardm@stripe.com> Co-authored-by: Dominic Charley-Roy <dcr@stripe.com> * Bump version to 9.2.0 * Codegen for openapi v146 (#1430) * Bump version to 9.3.0 * Codegen for openapi v147 (#1431) * Bump version to 9.4.0 * docs: Update HttpClient documentation to remove experimental status. (#1432) * Codegen for openapi v149 (#1434) * Bump version to 9.5.0 * API Updates (#1439) * Bump version to 9.6.0 * Update README.md (#1440) * Codegen for openapi v152 (#1441) * Add test for cash balance methods. (#1438) * Bump version to 9.7.0 Co-authored-by: Dominic Charley-Roy <78050200+dcr-stripe@users.noreply.github.com> Co-authored-by: Dominic Charley-Roy <dcr@stripe.com> Co-authored-by: Richard Marmorstein <52928443+richardm-stripe@users.noreply.github.com> Co-authored-by: Bruno Pinto <brunoferreirapinto@gmail.com> Co-authored-by: Richard Marmorstein <richardm@stripe.com> Co-authored-by: Kamil Pajdzik <99290280+kamil-stripe@users.noreply.github.com>
I also got this issue in v8, I upgraded to v9 and all looks good now automatically retry it is place now for |
Hello! |
We're using the stripe node client 8.71.0 on an AWS Lambda running node 12.x. A stripe customers.list call is called first thing when the lambda executes. 33% of the time - we get this error on that call. It consistently happens so does not seem to be transient.
I did read #650, and setting maxNetworkRetries in stripe to 2 seems to resolve the issue. However it seems that just masks the issue.
Is this a stripe issue or AWS Lambda issue? Probably lambda, I submitted a request with AWS. But putting this here in case others run into it.
2020-10-13T12:02:58.032Z c184006d-fe96-490a-9bfe-696b8271769a ERROR StripeConnectionError: An error occurred with our connection to Stripe.
at /var/task/node_modules/stripe/lib/StripeResource.js:234:9
at ClientRequest. (/var/task/node_modules/stripe/lib/StripeResource.js:489:67)
at ClientRequest.emit (events.js:315:20)
at ClientRequest.EventEmitter.emit (domain.js:483:12)
at TLSSocket.socketErrorListener (_http_client.js:426:9)
at TLSSocket.emit (events.js:315:20)
at TLSSocket.EventEmitter.emit (domain.js:483:12)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
type: 'StripeConnectionError',
raw: {
message: 'An error occurred with our connection to Stripe.',
detail: Error: write EPIPE
at WriteWrap.onWriteComplete [as oncomplete] (internal/stream_base_commons.js:92:16)
at writevGeneric (internal/stream_base_commons.js:132:26)
at TLSSocket.Socket._writeGeneric (net.js:784:11)
at TLSSocket.Socket._writev (net.js:793:8)
at doWrite (_stream_writable.js:401:12)
at clearBuffer (_stream_writable.js:519:5)
at TLSSocket.Writable.uncork (_stream_writable.js:338:7)
at ClientRequest.end (_http_outgoing.js:774:17)
at ClientRequest. (/var/task/node_modules/stripe/lib/StripeResource.js:506:15)
at Object.onceWrapper (events.js:422:26) {
errno: 'EPIPE',
code: 'EPIPE',
syscall: 'write'
}
},
rawType: undefined,
code: undefined,
doc_url: undefined,
param: undefined,
detail: Error: write EPIPE
at WriteWrap.onWriteComplete [as oncomplete] (internal/stream_base_commons.js:92:16)
at writevGeneric (internal/stream_base_commons.js:132:26)
at TLSSocket.Socket._writeGeneric (net.js:784:11)
at TLSSocket.Socket._writev (net.js:793:8)
at doWrite (_stream_writable.js:401:12)
at clearBuffer (_stream_writable.js:519:5)
at TLSSocket.Writable.uncork (_stream_writable.js:338:7)
at ClientRequest.end (_http_outgoing.js:774:17)
at ClientRequest. (/var/task/node_modules/stripe/lib/StripeResource.js:506:15)
at Object.onceWrapper (events.js:422:26) {
errno: 'EPIPE',
code: 'EPIPE',
syscall: 'write'
},
headers: undefined,
requestId: undefined,
statusCode: undefined,
charge: undefined,
decline_code: undefined,
payment_intent: undefined,
payment_method: undefined,
setup_intent: undefined,
source: undefined
}
The text was updated successfully, but these errors were encountered: