-
Notifications
You must be signed in to change notification settings - Fork 589
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
S3.send sometimes leads to application exit with code 0 #4332
Comments
Transferring to V3 repo of SDK |
Hi @bes,
I'm not sure what the "trick" is? Since there is no complete repro code I can't speak to why you are experiencing this, but it seems like you are not doing any sort of error handling. If the app crashes its probably due to an error coming from the server that you are not handling. try{
await s3.send(
new PutObjectCommand({
Bucket: bucket,
Key: toFile,
Body: data,
CacheControl: cacheControl,
ContentType: contentType ?? undefined,
}),
)
} catch (error){
console.log("there is an error! ", error)
} If after you've implemented error handling your app still crashes unexpectedly, please include a reproducible code snippet we can test on our end to see what can be done to help. Thank you! |
Hi @RanVaknin Thank you for your response. I am using error handling. A more complete example: const pushToS3 = async (semaphore: Semaphore, s3: S3, bucket: string, data: Buffer, toFile: string): Promise<void> => {
const release = await semaphore.acquire();
try {
// ... stuff
const t = setTimeout(() => console.log("This is printed just before exit code 0"), 5000);
const x = await s3.send(
new PutObjectCommand({
Bucket: bucket,
Key: toFile,
Body: data,
CacheControl: cacheControl,
ContentType: contentType ?? undefined,
}),
);
clearTimeout(t);
console.log("Intermittently never reached!");
} catch (e) {
console.log(e);
} finally {
release();
}
}; There is no error log. |
If I leave out |
We are on an AWS support plan, is there a way of sharing our code through support? |
Could it be a race condition in |
Hi @bes ,
Are you just using setTimeout here to isolate the issue?
You can, but I think you shouldn't. Those internal support tickets end up in our queue, and you will have to talk to us through a technical account manager. I recommend talking to us directly here.
Unless you're doing thousands of writes per second I don't think the service will throttle, and even if it does, it will throw some 5xx error that should be retried by the Retryer, and also logged to the console. The line Im suspecting is causing issues for you is the following one: As an experiment I've refactored your code and ran this successfully: // file named sample.js
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
const client = new S3Client({})
const pushToS3 = async (s3client, bucket, data, key, cacheControl, contentType) => {
try {
await s3client.send(
new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: data,
CacheControl: cacheControl,
ContentType: contentType ?? undefined,
}),
);
console.log("Intermittently never reached!");
} catch (e) {
console.log(e);
}
};
for (let i = 0; i < 20; i++) {
pushToS3(
client,
"testbucket-3650",
`hello-world${Date.now()}`, //unique body
`key${i}.txt`,
"max-age=99",
"text/html; charset=utf-8"
)
} Output: $ node sample.js
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached!
Intermittently never reached! Let me know if this helps. |
Hi @RanVaknin thank you for your suggestion. I have removed all uses of EDIT: Please note that it doesn't happen all the time. It's an intermittent issue. Between 1/5 to 1/20. |
This is a typical error flow: Intermittently never reached!
Intermittently never reached!
Timeout With exit code 0 |
Hi @bes, I spent quite a bit of time reading through the initial issue you linked from Node's repo. Additionally, I looked at how we handle http requests and I have not found a case in which we drop reference to the promise. From an error, to socket timeout, we handle all cases and raise the appropriate errors. I really think this is a Node issue based on how much traction that issue got on that thread. Another thing you can do is add an additional await after your s3.putObject call, to see if that one is called.
Unfortunately I'm not able to reproduce your issue with what we have so far. If you can provide a more comprehensive code sample that raises that error, even intermittently, I can try to dig deeper into the issue at hand. Thank you! |
Thank you for your effort! May I ask what version of node you used when you tested? I want to try again with that same version on my code. |
Hi @bes, My pleasure, I use Node 18.0.0. Thanks, |
@RanVaknin Alright here is a minimal proof of concept that gives exit code 0 within a few seconds: https://github.com/bes/aws-sdk-js-v3-s3-exit-0 How I ran it: AWS Credentials Node / Yarn Install command: Run command: Output: yarn run v1.22.19
$ TS_NODE_PROJECT="tsconfig.json" ts-node build.ts
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
✨ Done in 4.50s. |
Hi @bes, Thanks for providing me with the repo. I refactored your code a bit and let the program run for about 5-6 minutes before stopping it. I usually use unique Object bodies when testing because otherwise the Etag would be the same, and it would be harder to debug. So Something like: Body: `hello ${Date.now()}` The only time my application crashed was when I ran the request with an empty buffer like in your example:
The error I got was node[42307]: ../src/node_http_parser.cc:589:static void node::(anonymous namespace)::Parser::Execute(const FunctionCallbackInfo<v8::Value> &): Assertion `parser->current_buffer_.IsEmpty()' failed.
1: 0x1025c2e28 node::Abort() [/Users/rvaknin/.nvm/versions/node/v18.0.0/bin/node]
2: 0x1025c2c68 node::AppendExceptionLine(node::Environment*, v8::Local<v8::Value>, v8::Local<v8::Message>, node::ErrorHandlingMode) [/Users/rvaknin/.nvm/versions/node/v18.0.0/bin/node]
3: 0x1025dc004 node::(anonymous namespace)::Parser::Execute(v8::FunctionCallbackInfo<v8::Value> const&) [/Users/rvaknin/.nvm/versions/node/v18.0.0/bin/node]
4: 0x102785274 v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) [/Users/rvaknin/.nvm/versions/node/v18.0.0/bin/node]
5: 0x102784d58 v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/Users/rvaknin/.nvm/versions/node/v18.0.0/bin/node]
6: 0x1027845e4 v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) [/Users/rvaknin/.nvm/versions/node/v18.0.0/bin/node]
7: 0x102f57a2c Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit [/Users/rvaknin/.nvm/versions/node/v18.0.0/bin/node]
8: 0x102ee1b98 Builtins_InterpreterEntryTrampoline [/Users/rvaknin/.nvm/versions/node/v18.0.0/bin/node]
...
...
...
... And this went away when I commented out Thanks, |
@RanVaknin There is only one main()
.then(() => {
console.log("Build done");
// process.exit(0);
})
.catch((e) => {
console.error(e);
// process.exit(-1);
}); I removed that one, and the poc failed again with exit code 0 I have a setup where I need to create an "empty file" on S3, it is used as a marker of sorts. It is surprising that this error should happen with empty files, actually it should exit with at least a stack trace. But it doesn't for me, unless I am misunderstanding something. Feel free to create a branch on my poc git with how you get an error / crash / stack trace. |
Example ~/web-aws-issue% git --no-pager diff 255 ↵
diff --git a/build.ts b/build.ts
index 16de02a..6c3b6e8 100644
--- a/build.ts
+++ b/build.ts
@@ -66,9 +66,9 @@ const pushToS3 = async (s3: S3, bucket: string, data: Buffer, toFile: string): P
main()
.then(() => {
console.log("Build done");
- process.exit(0);
+ // process.exit(0);
})
.catch((e) => {
console.error(e);
- process.exit(-1);
+ // process.exit(-1);
});
09:23:27 bes ‹master* M›
~/web-aws-issue% yarn run poc
yarn run v1.22.19
$ TS_NODE_PROJECT="tsconfig.json" ts-node build.ts
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
DONE
START
Missing Content-Type for test/2, defaulting to application/octet-stream
Uploading s3://bucket-xyz-example/test/2 [Content-Type: application/octet-stream, Cache-Control: undefined]
✨ Done in 1.84s. As you can see, it failed on the second upload. It shouldn't matter that I am pushing to "the same file" or that I am using "an empty file". It just shouldn't behave this way? |
Could anyone please suggest a workaround? It's been more than a year and I see no fix. It causes Electron to crash and we can't ship a product like that. aws-sdk v3 is useless for us due to this error, and v2 uses old version of libs that we don't want to risk security. It is nice that at least we have a workaround. I commented this out on node repo and they suggest that it is AWS SDK. I believe they are right, but I am not sure how AWS can cause such a crash in Node.js. It seems this is happening more often with choppy or slow internet connection. |
I confirm it happens on a slow internet more often, I've tested it with slow mobile data. aws-sdk-js-v3/packages/middleware-retry/src/retryMiddleware.ts Lines 59 to 71 in 2fa1dd5
|
Based on marco-ippolito's answer, here are few potential lines that maybe problematic: Line 45:
Delay coming back from
Maybe falling back on V1 strategy and infinite recursion happen line 79 (
|
The process is not crashing, it is exiting because the event loop has no active handle. My guess is that there is a race condition.
|
I have a similar issue with the parallel downloading. import { S3Client, ListObjectsV2Command, GetObjectCommand } from '@aws-sdk/client-s3'
(async () => {
const client = new S3Client({
credentials:{
accessKeyId:'XXXXXXX',
secretAccessKey:'XXXXX'
},
region: "us-east-1"
})
const bucket_name = 'Bucket'
const input = {
Bucket: bucket_name,
}
const list = await client.send(new ListObjectsV2Command(input))
// Here I have 1000 files 38535294 bytes each
await Promise.all(
list.Contents.map(async file => {
console.log(`Downloading file ${file.Key} [...]`);
await client.send(
new GetObjectCommand({
Bucket: bucket_name,
Key: file.Key
}),
);
console.log(`File ${file.Key} downloaded`);
}),
);
//
// Doesn't reach this console.log(). The process exits after 50 downloads with exit status 13:
// "Unfinished Top-Level Await: await was used outside of a function in the top-level code,
// but the passed Promise never resolved."
//
console.log('All files downloaded!');
})(); |
We encountered this issue as well, but not while processing a loop but by invoking a lambda function multple times in a short period of time:
We implemented the following workaround to fix the issue for now:
Are other SDK clients send functions also impacted by this issue or is the s3 send function the only one? |
I've opened a PR to fix this #4492 |
could someone who was previously able to reproduce this check if it's present in the latest version? https://github.com/aws/aws-sdk-js-v3/releases/tag/v3.337.0 An attempted fix was released based on the information in this issue, but since I wasn't able to reproduce it using the samples, I can't tell whether it's working. |
This issue has not received a response in 1 week. If you still think there is a problem, please leave a comment to avoid the issue from automatically closing. |
Hi @bes @bracki @mohghaderi @heikowissmann @dozzes, Can you please test with latest release to see if this is solved? Thanks, |
I started having a similar error when I put Caddy in front of minio (open source S3 server). I used Caddy as a reverse proxy to terminate TLS. Here's my error:
That error lead me to this AWS SDK v2 issue: aws/aws-sdk-js#3674 I realized that AWS SDK v3 was also using |
@RanVaknin It passed our QA process, and we could upload several GB of test data to AWS S3 without any error (v3.348.0). Thanks. |
Hi there! I have observed similar behaviour with the process exiting without explanation using the following code: import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
const BUCKET = "some bucket";
const KEY = "some key";
const REGION = "some region";
const log = (message: string) => {
console.log(`${new Date().toISOString()}: ${message}`);
};
const loadTest = async () => {
const s3Client = new S3Client({ region: REGION });
let requestCount = 0;
while (true) {
requestCount += 1;
const requestStartTime = performance.now();
log(`Request ${requestCount} beginning`);
try {
await s3Client.send(new GetObjectCommand({ Bucket: BUCKET, Key: KEY }));
} catch (e) {
console.log(e);
}
const requestEndTime = performance.now();
const requestDuration = requestEndTime - requestStartTime;
log(
`Request ${requestCount} completed in ${Math.round(requestDuration)}ms`
);
}
};
loadTest(); When running, it seems to make exactly 50 successful requests, and the exits with code 0 on the 51st one. There are no errors. Log output:
This seems very unusual, and concerns me that this could happen in our production servers - with absolutely no trace of why the process has exited. Hopefully this information helps! |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread. |
Describe the bug
Executing this code...
...in the middle of a long chain of awaits sometimes leads to application exit with code
0
.I believe this may be because of the behavior described here: nodejs/node#22088
Basically, I think,
s3.send
somehow drops both its handle toresolve
andreject
, dropping the reference count of scheduled requests in the node runtime to 0, which in turn automatically exits node with code0
.This took a long time to figure out and is very confusing when encountering it for the first time.
The reason I think this is what happens, is because when i use the
setTimeout
trick, the application stays alive untilsetTimeout
triggers and then immediately exits with code0
.Example of this:
It seems to happen more often on 4G connections than on WiFi.
Expected Behavior
An actual error to be thrown or printed.
Current Behavior
My node application exits with code 0 even though all code has not been run yet.
Reproduction Steps
Since the error is intermittent, and I have a lot of proprietary code, I can't give a better example than this:
Possible Solution
Hopefully the code in the
aws-sdk-js
repository can be fixed.Additional Information/Context
No response
SDK version used
3.245.0
Environment details (OS name and version, etc.)
macOS 13.0.1 (22A400)
node v18.8.0
scripts compiled & run using ts-node
The text was updated successfully, but these errors were encountered: