Skip to content
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

Async operation before send #158

Open
eXist-FraGGer opened this issue Aug 4, 2020 · 6 comments
Open

Async operation before send #158

eXist-FraGGer opened this issue Aug 4, 2020 · 6 comments

Comments

@eXist-FraGGer
Copy link

eXist-FraGGer commented Aug 4, 2020

Hello everyone!

I need to save some important data every time when the response is already available.

I have tried 2 approaches:

  1. api.finally - does not allow us to use an async callback.
api.finally(async (req, res) => {
  await saveAudit(req, res)
  res.cors()
  console.log('done')
})
  1. Tried to override the method res.send in a middleware - it looks like the send method can not include any async operations.
function auditHandler (handler) {
  return (req, res, next) => {
    res.sendRes= res.send
    res.send = function (body) {
      const data = {}
      saveAudit(data)
      .finally(() => {
        console.log('finally', resData)
        res.sendRes.call(this, body)
      })
    }
    next()
  }
}

As a result - the API does not work, but it works if we do not wait for an asynchronous operation.

image

@MarioVerbelen
Copy link

Interesting topic,
I was thinking for something like middleware but then before the send

My use-case was that I would like to create a function for cache headers depending of the status code
For that you need access to the response details, like statusCode, current headers etc

@eXist-FraGGer
Copy link
Author

eXist-FraGGer commented Aug 4, 2020

I have checked the source code and see why it does not work

The api.finally supports async callback
image

But the method res.send does not wait for the async method _callback

image

@eXist-FraGGer
Copy link
Author

It works if we do the next changes:

image
2.
image

@eXist-FraGGer
Copy link
Author

There is a way how to do some async operations in finally.

  1. Use callback from lambda function
module.exports.handler = (event, context, callback) => {
  api.run(event, context, callback)
}
  1. Use async operation in api.finally - !!! important - do not use async / await
api.finally((req, res) => {
  saveAudit().finally(() => { console.log('done') })
})
  1. Why it works:
    The third argument, callback, is a function that you can call in non-async handlers to send a response. The callback function takes two arguments: an Error and a response. When you call it, Lambda waits for the event loop to be empty and then returns the response or error to the invoker.

https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html

@MarioVerbelen
Copy link

api.finally((req, res) ... works great

I see that in the handler you can also use then on run

return api.run(event, context)
    .then(res => {
        console.log(res);
        do stuff...;
        return res;
    })

@ammulder
Copy link

ammulder commented May 6, 2022

I too wish that finally could take an async function. I put the MySQL pool (from, ahem, jeremydaly/serverless-mysql) into a request field, and finally gets passed the request object, so it would be the better way to clean up afterward.

For now, instead, I keep the pool in a global variable and assign it to the request but clean up in the handler function:

const api = createAPI({logger: {access: true}});
api.use((req, res, next) => {
  req.mysql = prepareMySQL();
  next();
});

const func: APIGatewayProxyHandlerV2WithJWTAuthorizer = async
                      (event:APIGatewayProxyEventV2WithJWTAuthorizer, context:Context):
                      Promise<APIGatewayProxyStructuredResultV2> => {
  const result = await api.run(event, context);
  await cleanUpMySQL();
  return result;
}

export default func;

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

No branches or pull requests

3 participants