From the documentation, AWS Lambda will retry failed function on stream-based events sources.
By using Node.js, we can fail the function by many different ways, e.g. using callback to return error, throw exception directly, throw exception inside Promise, using Promise.reject. Then the questions is, what’s the proper way to let AWS Lambda know it needs a retry?
I did an quick test on following scenarios by setting up DynamoDB Stream and event mappings. It’s fun to have a guess which one will be retried and which one won’t.
Different ways to end the function
- On Exception
module.exports.throwException = (event, context) => { console.log(JSON.stringify(event)); throw new Error('something wrong'); };
- Using callback to return Success
module.exports.success = (event, context, callback) => { console.log(JSON.stringify(event)); callback(null, 'result'); };
- Using callback to return Error
module.exports.returnFailure = (event, context, callback) => { console.log(JSON.stringify(event)); callback('error occurred'); };
- On Promise Reject
module.exports.throwException = (event, context) => { console.log(JSON.stringify(event)); Promise.resolve('') .then(() => Promise.reject('something wrong')); };
- Returning Promise Reject
module.exports.throwException = (event, context) => { console.log(JSON.stringify(event)); return Promise.resolve('') .then(() => Promise.reject('something wrong')); };
- Catch Promise Reject and using callback to return error
module.exports.throwException = (event, context, callback) => { console.log(JSON.stringify(event)); Promise.resolve('') .then(() => Promise.reject('something wrong')) .catch((err) => callback(err)) };
- Throw Error inside Promise
module.exports.throwException = (event, context) => { console.log(JSON.stringify(event)); Promise.resolve('') .then(() => { throw new Error('something wrong'); }); };
- Catch Error using Promise and using callback to return error
module.exports.throwException = (event, context, callback) => { console.log(JSON.stringify(event)); Promise.resolve('') .then(() => { throw new Error('something wrong'); }) .catch(err => callback(err)); };
AWS Lambda Retry behaviours
Here’s the result, only the following functions will be retried:
- Using callback to Return Error:
callback(null, 'result');
-
On Exception outside Promise:
throw new Error()
-
Catch Promise Reject and using callback to return error :
Promise.resolve('') .then(() => Promise.reject('something wrong')) .catch((err) => callback(err))
- Catch Error using Promise and using callback to return error
Promise.resolve('') .then(() => { throw new Error('something wrong'); }) .catch(err => callback(err));
In conclusion, it will retry if failed by callback function or Error thrown outside Promise. To make it simple, clear and consistent, It would be nice to always return result using callback.