Skip to content

Commit f3d9411

Browse files
committed
Initial commit
0 parents  commit f3d9411

File tree

11 files changed

+1907
-0
lines changed

11 files changed

+1907
-0
lines changed

.editorconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = space
6+
indent_size = 2
7+
insert_final_newline = true
8+
trim_trailing_whitespace = true

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = { "extends": "standard" };

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.vs/
2+
.vscode/
3+
.serverless/
4+
node_modules/
5+
example/.vscode/
6+
example/.serverless/
7+
example/node_modules/

.npmignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.vscode/
2+
node_modules/
3+
example/
4+
.editorconfig
5+
.eslintrc.js

README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Failure injection for AWS Lambda - failure-lambda
2+
3+
## Description
4+
5+
`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.
6+
7+
## How to install
8+
9+
1. Install `failure-lambda` module using NPM.
10+
```bash
11+
npm install failure-lambda
12+
```
13+
2. Add the module to your Lambda function code.
14+
```js
15+
const failureLambda = require('failure-lambda')
16+
```
17+
3. Wrap your handler.
18+
```js
19+
exports.handler = failureLambda(async (event, context) => {
20+
...
21+
})
22+
```
23+
4. Create a parameter in SSM Parameter Store.
24+
```json
25+
{"isEnabled": false, "failureMode": "latency", "rate": 1, "minLatency": 100, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404}
26+
```
27+
```bash
28+
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}"
29+
```
30+
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.
31+
6. Try it out!
32+
33+
## Usage
34+
35+
Edit the values of your parameter in SSM Parameter Store to use the failure injection module.
36+
37+
* `isEnabled: true` means that failure is injected into your Lambda function.
38+
* `isEnabled: false` means that the failure injection module is disabled and no failure is injected.
39+
* `failureMode` selects which failure you want to inject. The options are `latency`, `exception` or `statuscode` as explained below.
40+
* `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.
41+
* `minLatency` and `maxLatency` is the span of latency in milliseconds injected into your function when `failureMode` is set to `latency`.
42+
* `exceptionMsg` is the message thrown with the exception created when `failureMode` is set to `exception`.
43+
* `statusCode` is the status code returned by your function when `failureMode` is set to `statuscode`.
44+
45+
## Example
46+
47+
In the subfolder `example` is a simple Serverless Framework template which will install a Lambda function and a parameter in SSM Parameter Store.
48+
```bash
49+
npm install failure-lambda
50+
sls deploy
51+
```
52+
53+
## Changelog
54+
55+
### 2019-12-23 v0.0.1
56+
57+
* Initial release
58+
59+
## Authors
60+
61+
**Gunnar Grosch** - [GitHub](https://github.com/gunnargrosch) | [Twitter](https://twitter.com/gunnargrosch) | [LinkedIn](https://www.linkedin.com/in/gunnargrosch/)

example/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = { "extends": "standard" };

example/index.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict'
2+
const failureLambda = require('failure-lambda')
3+
let response
4+
5+
exports.handler = failureLambda(async (event, context) => {
6+
try {
7+
response = {
8+
statusCode: 200,
9+
body: JSON.stringify({
10+
message: 'Hello failureLambda!'
11+
})
12+
}
13+
} catch (err) {
14+
console.log(err)
15+
return err
16+
}
17+
18+
return response
19+
})

example/serverless.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
service: failureLambdaExample
2+
frameworkVersion: ">=1.34.0 <2.0.0"
3+
provider:
4+
name: aws
5+
runtime: nodejs10.x
6+
memorySize: 128
7+
iamRoleStatements:
8+
- Effect: Allow
9+
Action:
10+
- ssm:GetParameters
11+
- ssm:GetParameter
12+
Resource: "arn:aws:ssm:${opt:region, self:provider.region}:*:parameter/${self:service}-${opt:stage, self:provider.stage}-failureLambdaExample"
13+
functions:
14+
failureLambdaExample:
15+
handler: index.handler
16+
timeout: 3
17+
environment:
18+
FAILURE_INJECTION_PARAM:
19+
Ref: failureLambdaParameter
20+
events:
21+
- http:
22+
path: failureLambdaExample/
23+
method: get
24+
cors: true
25+
resources:
26+
Resources:
27+
failureLambdaParameter:
28+
Type: 'AWS::SSM::Parameter'
29+
Properties:
30+
Name: ${self:service}-${opt:stage, self:provider.stage}-failureLambdaExample
31+
Type: String
32+
Value: '{"isEnabled": false, "failureMode": "latency", "rate": 1, "minLatency": 100, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404}'
33+
package:
34+
exclude:
35+
- .vscode
36+
- .serverless

lib/failure.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict'
2+
const aws = require('aws-sdk')
3+
const ssm = new aws.SSM()
4+
5+
async function getConfig () {
6+
try {
7+
let params = {
8+
Name: process.env.FAILURE_INJECTION_PARAM
9+
}
10+
let request = await ssm.getParameter(params).promise()
11+
return request.Parameter.Value
12+
} catch (err) {
13+
console.error(err)
14+
throw err
15+
}
16+
}
17+
var injectFailure = function (fn) {
18+
return async function () {
19+
try {
20+
let configResponse = await getConfig()
21+
let config = JSON.parse(configResponse)
22+
if (config.isEnabled === true && Math.random() < config.rate) {
23+
if (config.failureMode === 'latency') {
24+
let latencyRange = config.maxLatency - config.minLatency
25+
let setLatency = Math.floor(config.minLatency + Math.random() * latencyRange)
26+
console.log('Injecting ' + setLatency + ' ms latency.')
27+
await new Promise(resolve => setTimeout(resolve, setLatency))
28+
} else if (config.failureMode === 'exception') {
29+
console.log('Injecting exception message: ' + config.exceptionMsg)
30+
throw new Error(config.exceptionMsg)
31+
} else if (config.failureMode === 'statuscode') {
32+
console.log('Injecting status code: ' + config.statusCode)
33+
let response = { statusCode: config.statusCode }
34+
return response
35+
}
36+
}
37+
return fn.apply(this, arguments)
38+
} catch (ex) {
39+
console.log(ex)
40+
}
41+
}
42+
}
43+
44+
module.exports = injectFailure

0 commit comments

Comments
 (0)