Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
gunnargrosch committed Dec 23, 2019
0 parents commit f3d9411
Show file tree
Hide file tree
Showing 11 changed files with 1,907 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { "extends": "standard" };
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.vs/
.vscode/
.serverless/
node_modules/
example/.vscode/
example/.serverless/
example/node_modules/
5 changes: 5 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.vscode/
node_modules/
example/
.editorconfig
.eslintrc.js
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Failure injection for AWS Lambda - failure-lambda

## Description

`failure-lambda` is a small Node module for injecting failure into AWS Lambda (https://aws.amazon.com/lambda). It offers a simple failure injection wrapper for your Lambda handler where you then can choose to inject failure by setting the `failureMode` to `latency`, `exception` or `statuscode`. You control your failure injection using SSM Parameter Store.

## How to install

1. Install `failure-lambda` module using NPM.
```bash
npm install failure-lambda
```
2. Add the module to your Lambda function code.
```js
const failureLambda = require('failure-lambda')
```
3. Wrap your handler.
```js
exports.handler = failureLambda(async (event, context) => {
...
})
```
4. Create a parameter in SSM Parameter Store.
```json
{"isEnabled": false, "failureMode": "latency", "rate": 1, "minLatency": 100, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404}
```
```bash
aws ssm put-parameter --region eu-north-1 --name failureLambdaConfig --type String --overwrite --value "{\"isEnabled\": false, \"failureMode\": \"latency\", \"rate\": 1, \"minLatency\": 100, \"maxLatency\": 400, \"exceptionMsg\": \"Exception message!\", \"statusCode\": 404}"
```
5. Add an environment variable to your Lambda function with the key FAILURE_INJECTION_PARAM and the value set to the name of your parameter in SSM Parameter Store.
6. Try it out!

## Usage

Edit the values of your parameter in SSM Parameter Store to use the failure injection module.

* `isEnabled: true` means that failure is injected into your Lambda function.
* `isEnabled: false` means that the failure injection module is disabled and no failure is injected.
* `failureMode` selects which failure you want to inject. The options are `latency`, `exception` or `statuscode` as explained below.
* `rate` controls the rate of failure. 1 means that failure is injected on all invocations and 0.5 that failure is injected on about half of all invocations.
* `minLatency` and `maxLatency` is the span of latency in milliseconds injected into your function when `failureMode` is set to `latency`.
* `exceptionMsg` is the message thrown with the exception created when `failureMode` is set to `exception`.
* `statusCode` is the status code returned by your function when `failureMode` is set to `statuscode`.

## Example

In the subfolder `example` is a simple Serverless Framework template which will install a Lambda function and a parameter in SSM Parameter Store.
```bash
npm install failure-lambda
sls deploy
```

## Changelog

### 2019-12-23 v0.0.1

* Initial release

## Authors

**Gunnar Grosch** - [GitHub](https://github.com/gunnargrosch) | [Twitter](https://twitter.com/gunnargrosch) | [LinkedIn](https://www.linkedin.com/in/gunnargrosch/)
1 change: 1 addition & 0 deletions example/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { "extends": "standard" };
19 changes: 19 additions & 0 deletions example/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict'
const failureLambda = require('failure-lambda')
let response

exports.handler = failureLambda(async (event, context) => {
try {
response = {
statusCode: 200,
body: JSON.stringify({
message: 'Hello failureLambda!'
})
}
} catch (err) {
console.log(err)
return err
}

return response
})
36 changes: 36 additions & 0 deletions example/serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
service: failureLambdaExample
frameworkVersion: ">=1.34.0 <2.0.0"
provider:
name: aws
runtime: nodejs10.x
memorySize: 128
iamRoleStatements:
- Effect: Allow
Action:
- ssm:GetParameters
- ssm:GetParameter
Resource: "arn:aws:ssm:${opt:region, self:provider.region}:*:parameter/${self:service}-${opt:stage, self:provider.stage}-failureLambdaExample"
functions:
failureLambdaExample:
handler: index.handler
timeout: 3
environment:
FAILURE_INJECTION_PARAM:
Ref: failureLambdaParameter
events:
- http:
path: failureLambdaExample/
method: get
cors: true
resources:
Resources:
failureLambdaParameter:
Type: 'AWS::SSM::Parameter'
Properties:
Name: ${self:service}-${opt:stage, self:provider.stage}-failureLambdaExample
Type: String
Value: '{"isEnabled": false, "failureMode": "latency", "rate": 1, "minLatency": 100, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404}'
package:
exclude:
- .vscode
- .serverless
44 changes: 44 additions & 0 deletions lib/failure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict'
const aws = require('aws-sdk')
const ssm = new aws.SSM()

async function getConfig () {
try {
let params = {
Name: process.env.FAILURE_INJECTION_PARAM
}
let request = await ssm.getParameter(params).promise()
return request.Parameter.Value
} catch (err) {
console.error(err)
throw err
}
}
var injectFailure = function (fn) {
return async function () {
try {
let configResponse = await getConfig()
let config = JSON.parse(configResponse)
if (config.isEnabled === true && Math.random() < config.rate) {
if (config.failureMode === 'latency') {
let latencyRange = config.maxLatency - config.minLatency
let setLatency = Math.floor(config.minLatency + Math.random() * latencyRange)
console.log('Injecting ' + setLatency + ' ms latency.')
await new Promise(resolve => setTimeout(resolve, setLatency))
} else if (config.failureMode === 'exception') {
console.log('Injecting exception message: ' + config.exceptionMsg)
throw new Error(config.exceptionMsg)
} else if (config.failureMode === 'statuscode') {
console.log('Injecting status code: ' + config.statusCode)
let response = { statusCode: config.statusCode }
return response
}
}
return fn.apply(this, arguments)
} catch (ex) {
console.log(ex)
}
}
}

module.exports = injectFailure
Loading

0 comments on commit f3d9411

Please sign in to comment.