serverless-express: Async handler doesn't work on node 8.10
I have reduced my project to that snippet which generates an error using the new 8.10:
import awsServerlessExpress from 'aws-serverless-express'
import express from 'express'
export default async (event, context, callback) => {
const app = express()
app.get('/', function(req, res){
res.send('hello world')
})
const server = awsServerlessExpress.createServer(app)
return awsServerlessExpress.proxy(server, event, context)
}
Babel compilation targets node 8.10 to be sure it doesn’t convert async/await to native js code.
Cloudwatch reports:
START RequestId: 3cb224ae-3810-11e8-ba0f-437e442fcf6a Version: $LATEST
Unable to stringify response body as json: Converting circular structure to JSON: TypeError
END RequestId: 3cb224ae-3810-11e8-ba0f-437e442fcf6a
REPORT RequestId: 3cb224ae-3810-11e8-ba0f-437e442fcf6a Duration: 30027.56 ms Billed Duration: 30000 ms Memory Size: 512 MB Max Memory Used: 31 MB
Removing the async
in the handler fix the problem. But my whole project does some await
in the handler which requires the handler to be async.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 13
- Comments: 37
Commits related to this issue
- feat: use async/await + change from serverless-http to aws-serverless-express reference to https://github.com/awslabs/aws-serverless-express/issues/134 — committed to AKIRA-MIYAKE/serverless-oidc-provider by AKIRA-MIYAKE 6 years ago
- remove debugging logging from the s3-credentials-endpoint, make the handler _not_ async — committed to nasa/cumulus by ifestus 5 years ago
- handlerをasyncにする場合、"PROMISE"が必要だった。 https://github.com/awslabs/aws-serverless-express/issues/134#issuecomment-412935564 — committed to nacam403/typescript-study by nacam403 4 years ago
PR for this here https://github.com/awslabs/aws-serverless-express/pull/173. Note that I plan on improving the interface in a future breaking change (aws-serverless-express 4.0.0), but for now this is a backwards compatible change with the following interface:
module.exports = awsServerlessExpress.proxy(server, event, context, 'PROMISE').promise
should workI’ve tried what @brettstack said and it works (I’m using
serverless-offline
so I useprocess.env.IS_OFFLINE
to pass correct handler toaws-serverless-express
):I have it working in a local branch. Going to go with a non-breaking change and we’ll improve the overall API of this project in the future in a major version bump. I first want to add some additional integration tests before I merge in support. SAM has been taking priority for me lately, but I do want to get this in. For now I suggest patching in support https://github.com/awslabs/aws-serverless-express/issues/134#issuecomment-379417431
I’m now supporting this project again. V4 RCs are available http://npmjs.com/package/@vendia/serverless-express
Released in v3.3.3
Thanks. We’re working towards v4 where this will be the default.
With @brettstack no longer at AWS it seems development here has stalled. Will plans for V4 be resurrected?
Hey, thanks for providing the solution here !
Having this: https://github.com/awslabs/aws-serverless-express/issues/134#issuecomment-495026574
In the Readme or a sample would help big time for future users.
So, what is the relevant solution ? 3.3.6 tried everything from this discussion and still can’t get async handler working (
Oh great! Yeah I’m aware of the
.promise()
in the AWS SDK already. Sorry to bother you I didn’t took the time to check the code. Thanks!@j0k3r @Bnaya
Sorry, I goofed the guidance in that comment (now updated). Tack a
.promise
at the end of that line and you should be good to go.Here’s the test which covers this https://github.com/awslabs/aws-serverless-express/blob/master/__tests__/integration.js#L196-L200
And here’s the implementation https://github.com/awslabs/aws-serverless-express/blob/master/src/index.js#L210-L230
You can see I’m returning
{ promise: new Promise...
instead of returningnew Promise...
directly. This decision was made for future extensibility.I’ll give a try tomorrow. Thanks @josephktcheung to confirm that it worked.
Regarding moving stuff outside the handler, we usually do sth like that:
Otherwise I don’t know how can you move
await configureApp(app);
outside the handler since it’s an async call.Okay so the problem is that Node.js 8.10 now allows you to resolve using Promises instead of the old
callback
and even oldercontext.succeed
(which this library uses). We did have a path forward for upgrading fromcontext.succeed
tocallback
by settingcontext.callbackWaitsForEmptyEventLoop = true
(see #32) however, the new Promise pattern ignores that.For now, you can’t use Node.js 8.10 with an async handler (or return a promise). I’ll update the library to work with the latest updates soon. Based on the examples you’ve provided so far, it’s recommended to perform these setup tasks outside of the handler for best performance (that way these things happen only on cold start, and not on every invocation)
I switched to what you did (and upgraded to 3.3.5):
But now the APIGW returns 502 all the time. No error in log 😕