undici
undici copied to clipboard
Fetch times out without AbortController triggered
Bug Description
Hello, I'm trying to create a custom AWS lambda container runtime as a small hobby project. And since fetch is now part of the core NodeJS I wanted to give it a try. To get the lambda invocations, I need a request with a really long timeout, so I did set up an AbortController that will never be triggered:
function getNextInvocation() {
return fetch(`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next`, {
signal: new AbortController().signal,
});
}
When I uploaded my code to aws (as a container image). And tested it, the first execution was fine, but after a few minutes I retried and got:
TypeError: fetch failed
at Object.processResponse (node:internal/deps/undici/undici:7156:34)
at Fetch.fetchFinale (node:internal/deps/undici/undici:7486:21)
at Fetch.mainFetch (node:internal/deps/undici/undici:7380:21)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
cause: HeadersTimeoutError: Headers Timeout Error
at Timeout.onParserTimeout [as _onTimeout] (node:internal/deps/undici/undici:2109:33)
at listOnTimeout (node:internal/timers:561:11)
at processTimers (node:internal/timers:502:7) {
code: 'UND_ERR_HEADERS_TIMEOUT'
}
}
Reproducible By
Full snippet of my test code:
const {
AWS_LAMBDA_RUNTIME_API
} = process.env;
function getNextInvocation() {
return fetch(`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next`, {
signal: new AbortController().signal,
});
}
function postResults(result, reqId) {
return fetch(`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/${reqId}/response`, {
body: typeof result === 'object' ? JSON.stringify(result) : result,
method: 'post'
});
}
async function runIteration() {
const invocation = await getNextInvocation();
await postResults('OK', invocation.headers.get('Lambda-Runtime-Aws-Request-Id'));
}
async function loop() {
while (true) {
await runIteration();
}
}
loop();
Expected Behavior
If the abort controller is never triggered, I'd expect to never receive a timeout error.
Logs & Screenshots
Environment
I uploaded the above code to AWS ECR and ran it in lambda as container image. My dockerfile is
FROM node:17.8-alpine
COPY *.js .
CMD ["node", "--experimental-fetch", "index.js"]
Additional context
This would be expected given the AWS lambda runtime. The process got suspended and you had a timeout for a response. I think you'll have to catch with this error and retry the call.
So you say it is not possible to just wait infinitely for a possible response? I might not remember correctly but I think when using the https library in Node I was able to pass in timeout infinity and never see similar problems. I think when AWS shots down my lambda process it totally kills it, when when running it again for the first time after some delay, it boots up a new container from the image. In that case the code (in theory) should work as for the first invocation (when it succeeds)
Try catch + retry should work, I just wanted to avoid it, if its possible to solve it with passing an option parameter
Lambdas do have a limit on execution time: https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html#function-configuration-deployment-and-execution 900seconds.