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

How to cause error in Lambda? #171

Closed
cujarrett opened this issue Feb 15, 2021 · 2 comments
Closed

How to cause error in Lambda? #171

cujarrett opened this issue Feb 15, 2021 · 2 comments

Comments

@cujarrett
Copy link

To take advantage of monitoring and on error events in Lambda, I can't seem to cause anything to show a Lamba error.

Could we talk through how to accomplish this with the projects example?

// Require the framework and instantiate it
const api = require('lambda-api')()

// Define a route
api.get('/status', async (req,res) => {
  return { status: 'ok' }
})

// Declare your Lambda handler
exports.handler = async (event, context) => {
  // Run the request
  return await api.run(event, context)
}

I've tried these:

const api = require('lambda-api')()

api.get('/1', (req,res) => {
  res.error('This is an error')
})

api.get('/2', (req,res) => {
  res.error(403,'Not authorized')
})

api.get('/3', (req,res) => {
  res.error('Error', { foo: 'bar' })
})

api.get('/4', (req,res) => {
  res.error(404, 'Page not found', 'foo bar')
})

api.get('/5', (req,res, callback) => {
  callback("errorResponse", null)
})

api.get('/6', (req,res, callback) => {
  callback(null, "errorResponse")
})

api.get('/7', (req,res, callback) => {
  throw new Error("errorResponse")
})

exports.handler = async (event, context) => {
  return await api.run(event, context)
}

Screen Shot 2021-02-14 at 6 09 39 PM

@stawecki
Copy link

stawecki commented Feb 15, 2021

This is an interesting issue, as there are a couple of things to consider:

1. What kind of errors you want to see as Lambda errors?

For example res.error(403,'Not authorized') is an error that indicates to the client that they don't have access to the resource, but your lambda has executed correctly. Whereas throw new Error("errorResponse") could be an unexpected issue in your code that's causing the lambda to be executed incorrectly, perhaps due to a database issue or an unexpected set of parameters. The first error is not as critical, since your lambda is working correctly. The latter is something you want to be alerted of, since it might point at a code or system issue that needs fixing. As you've pointed out, both are caught by Lambda API and passed onto the client through API Gateway deeming each execution as "Success". I believe aws-serverless-express handles this the same way. The only errors you might see as actual Lambda errors are time outs or out-of-memory crashes, which can point to code/system issues too.

2. How Lambda errors are handled by API Gateway?

Consider the following lambda:

exports.handler = async (event) => {
    return { statusCode: 500, body: JSON.stringify('Server Error') };
};

If you do a test run, you should see: "Execution result: succeeded"
API Gateway forwards your error response accordingly:

HTTP/2 500
content-type: application/json
[...]
"Server Error"

You've created an error response, but the Lambda itself hasn't experienced an error.
If you instead throw an error, you'll cause the lambda to fail:

exports.handler = async (event) => {
    throw new Error("Oh no");
};

Test returns: "Execution result: failed" and API Gateway returns:

HTTP/2 502
content-type: application/json
[...]
{"message": "Internal server error"}

One thing to notice is that any information from the thrown error object are hidden from the user, but will be visible on CloudWatch. In case of an HTTP error like 403/404, I don't believe there is a way to return those to API Gateway while also causing an actual Lambda error, without API Gateway sending the client a 502 instead (there may be some REST API configuration to achieve this that I'm not aware of). From that perspective, it seems safest for Lambda API to simply handle all errors and return an error response (code responsible for doing this: https://github.com/jeremydaly/lambda-api/blob/master/index.js#L252-L313).

3. How to best monitor different kinds of errors?

As I mentioned in my first point, it might not be a good idea to treat every error as a Lambda error, since it's a blunt tool when you want to separate the 4xx from the 5xx.
Currently I have two possible solutions to consider:

a) Throw 5xx errors as Lambda errors
I don't know, if this is supported by Lambda API itself (not that I'm aware of), but you could also do it yourself, by throwing an error before passing the response to your lambda e.g.

exports.handler = async (event, context) => {
    const result = await api.run(event, context)
    if (result.statusCode >= 500) { throw Error("Server Error"); }
    return result;
}

This is not ideal as you want the original error and its stack trace. Maybe someone else have managed to get around it. You'd have to log the actual result object to see the stack data collected by Lambda API in CloudWatch, either manually or by setting errorLogging and stack to true in Lambda API configuration (see https://github.com/jeremydaly/lambda-api#logging-configuration).
The client will see API Gateway's default 502 response.

b) Instead of using Lambda errors, use Lambda Insights.
If you log some of the error information, you can later analyze it with AWS CloudWatch Lambda Insights (https://aws.amazon.com/blogs/mt/introducing-cloudwatch-lambda-insights/).
It takes a bit of work to get into, but Lambda Insights will allow you to search and create metrics for different error types.
E.g. log some of the response information with: console.log(JSON.stringify({statusCode}));
Then run a query in Lambda Insights to look for a specific status code:

fields @timestamp, @message
| sort @timestamp desc
| limit 20
| filter statusCode = 404

If you've found an invocation that interests you, fetch the full log by requestId:

fields @timestamp, @message, @requestId
| sort @timestamp desc
| filter @requestId = "f5863eaa-4a0f-c32e-41ba-88fd20e9a180"

@cujarrett
Copy link
Author

Whereas throw new Error("errorResponse") could be an unexpected issue in your code that's causing the lambda to be executed incorrectly, perhaps due to a database issue or an unexpected set of parameters. The first error is not as critical, since your lambda is working correctly. The latter is something you want to be alerted of, since it might point at a code or system issue that needs fixing. As you've pointed out, both are caught by Lambda API and passed onto the client through API Gateway deeming each execution as "Success". I believe aws-serverless-express handles this the same way. The only errors you might see as actual Lambda errors are time outs or out-of-memory crashes, which can point to code/system issues too.

Yeah, I think my ask boils down to if I could have the error not caught by this package. I think I lose the ability to see Lambda errors (as shown in the picture in the description) and all Lambdas would lose the ability to have On Error events such as SNS notifying the app owners of app health issues.

Thank you for the thoughful response.

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

2 participants