Skip to content

Commit

Permalink
Fail action when Lambda function invocation fails (#6)
Browse files Browse the repository at this point in the history
Previously, failed Lambda invocations would be reported as successful.

This PR adds the input parameter `SUCCEED_ON_FUNCTION_FAILURE`, giving users the option to succeed in this action on function failure while changing the default action behavior to fail the action when the function fails.
  • Loading branch information
cyamonide committed Jul 5, 2020
1 parent 37bb5cf commit d3a63cc
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 20 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/* linguist-generated linguist-vendored=true
82 changes: 75 additions & 7 deletions __tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@ describe('invoke-aws-lambda', () => {
[Props.Qualifier]: 'production',
[ExtraOptions.HTTP_TIMEOUT]: '220000',
[ExtraOptions.MAX_RETRIES]: '3',
[ExtraOptions.SUCCEED_ON_FUNCTION_FAILURE]: 'false',
[Credentials.AWS_ACCESS_KEY_ID]: 'someAccessKey',
[Credentials.AWS_SECRET_ACCESS_KEY]: 'someSecretKey',
REGION: 'us-west-2',
};
getInput.mockImplementation(
(key: Partial<Props & Credentials & 'REGION'>) => {
return mockedInput[key];
}
);

beforeAll(() => {
getInput.mockImplementation(
(key: Partial<Props & Credentials & 'REGION'>) => {
return mockedInput[key];
}
);
});

afterEach(() => {
getInput.mockClear();
Expand All @@ -33,7 +37,7 @@ describe('invoke-aws-lambda', () => {
Lambda.__setResponseForMethods({ invoke: handler });

await main();
expect(getInput).toHaveBeenCalledTimes(12);
expect(getInput).toHaveBeenCalledTimes(13);
expect(setFailed).not.toHaveBeenCalled();
expect(AWS.config.httpOptions).toMatchInlineSnapshot(`
Object {
Expand Down Expand Up @@ -74,7 +78,7 @@ describe('invoke-aws-lambda', () => {
`);
});

it('fails when lambda throws an error', async () => {
it('fails when lambda invocation throws an error', async () => {
const handler = jest.fn(() => {
throw new Error('something went horribly wrong');
});
Expand All @@ -92,4 +96,68 @@ describe('invoke-aws-lambda', () => {
expect(setFailed).toHaveBeenCalled();
expect(setOutput).not.toHaveBeenCalled();
});

describe('when the function returns an error', () => {
beforeEach(() => {
const handler = jest.fn().mockReturnValue({
FunctionError: 'Unhandled',
});

Lambda.__setResponseForMethods({ invoke: handler });
});

it('should fail the action when SUCCEED_ON_FUNCTION_FAILURE is undefined', async () => {
const overriddenMockedInput = {
...mockedInput,
[ExtraOptions.SUCCEED_ON_FUNCTION_FAILURE]: undefined,
};

getInput.mockImplementation(
(key: Partial<Props & Credentials & 'REGION'>) => {
return overriddenMockedInput[key];
}
);

await main();

expect(setOutput).toHaveBeenCalled();
expect(setFailed).toHaveBeenCalled();
});

it('should fail the action when SUCCEED_ON_FUNCTION_FAILURE is false', async () => {
const overriddenMockedInput = {
...mockedInput,
[ExtraOptions.SUCCEED_ON_FUNCTION_FAILURE]: 'false',
};

getInput.mockImplementation(
(key: Partial<Props & Credentials & 'REGION'>) => {
return overriddenMockedInput[key];
}
);

await main();

expect(setOutput).toHaveBeenCalled();
expect(setFailed).toHaveBeenCalled();
});

it('should succeed the action when SUCCEED_ON_FUNCTION_FAILURE is true', async () => {
const overriddenMockedInput = {
...mockedInput,
[ExtraOptions.SUCCEED_ON_FUNCTION_FAILURE]: 'true',
};

getInput.mockImplementation(
(key: Partial<Props & Credentials & 'REGION'>) => {
return overriddenMockedInput[key];
}
);

await main();

expect(setOutput).toHaveBeenCalled();
expect(setFailed).not.toHaveBeenCalled();
});
});
});
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ inputs:
MAX_RETRIES:
description: Returns the maximum amount of retries to perform for a service request. By default this value is calculated by the specific service object that the request is being made to.
required: false
SUCCEED_ON_FUNCTION_FAILURE:
description: Set to true if this action should succeed when the Lambda function executed returns an error
required: false
outputs:
response: # id of output
description: "response from lambda invocation"
Expand Down
6 changes: 6 additions & 0 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion dist/src/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export declare enum ExtraOptions {
HTTP_TIMEOUT = "HTTP_TIMEOUT",
MAX_RETRIES = "MAX_RETRIES"
MAX_RETRIES = "MAX_RETRIES",
SUCCEED_ON_FUNCTION_FAILURE = "SUCCEED_ON_FUNCTION_FAILURE"
}
export declare enum Credentials {
AWS_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID",
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "invoke-aws-lambda",
"repository": "[email protected]:gagoar/invoke-aws-lambda.git",
"license": "MIT",
"version": "3.2.0",
"version": "3.3.0",
"description": "Invoke AWS Lambda",
"main": "index.ts",
"husky": {
Expand Down
21 changes: 11 additions & 10 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,17 @@ This action allows you to synchronously invoke a Lambda function and get the res

### Invocation

| Key | Type | Required | Description |
| ---------------- | :------------------------------------------: | :------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `FunctionName` | `string` | Yes | Name of the Lambda function to be invoked. |
| `InvocationType` | `RequestResponse\|`<br>`Event\|`<br>`DryRun` | No | Default `RequestResponse`. See the [AWS Javascript SDK docs](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property) for more info. |
| `LogType` | `Tail\|None` | No | Default `None`. Set to `Tail` to include the execution log in the response. |
| `Payload` | `string` | No | JSON that you want to provide to your Lambda function as input. |
| `Qualifier` | `string` | No | Version or alias of the function to be invoked. |
| `ClientContext` | `string` | No | Base64-encoded data about the invoking client to pass to the function. |
| `HTTP_TIMEOUT` | `number` | No | Sets the socket to timeout after timeout milliseconds of inactivity on the socket. Defaults to two minutes (120000). See the [AWS Javascript SDK docs](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html) |
| `MAX_RETRIES` | `number` | No | Returns the maximum amount of retries to perform for a service request. By default this value is calculated by the specific service object that the request is being made to. [AWS Javascript SDK docs](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html#maxRetries-property) |
| Key | Type | Required | Description |
| ----------------------------- | :------------------------------------------: | :------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `FunctionName` | `string` | Yes | Name of the Lambda function to be invoked. |
| `InvocationType` | `RequestResponse\|`<br>`Event\|`<br>`DryRun` | No | Default `RequestResponse`. See the [AWS Javascript SDK docs](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property) for more info. |
| `LogType` | `Tail\|None` | No | Default `None`. Set to `Tail` to include the execution log in the response. |
| `Payload` | `string` | No | JSON that you want to provide to your Lambda function as input. |
| `Qualifier` | `string` | No | Version or alias of the function to be invoked. |
| `ClientContext` | `string` | No | Base64-encoded data about the invoking client to pass to the function. |
| `HTTP_TIMEOUT` | `number` | No | Sets the socket to timeout after timeout milliseconds of inactivity on the socket. Defaults to two minutes (120000). See the [AWS Javascript SDK docs](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html) |
| `MAX_RETRIES` | `number` | No | Returns the maximum amount of retries to perform for a service request. By default this value is calculated by the specific service object that the request is being made to. [AWS Javascript SDK docs](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html#maxRetries-property) |
| `SUCCEED_ON_FUNCTION_FAILURE` | `boolean` | No | Set to true if this action should succeed when the Lambda function executed returns an error |

For more details on the parameters accepted by `Lambda.invoke()`, see the [AWS Javascript SDK](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property) docs

Expand Down
11 changes: 11 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const apiVersion = '2015-03-31';
export enum ExtraOptions {
HTTP_TIMEOUT = 'HTTP_TIMEOUT',
MAX_RETRIES = 'MAX_RETRIES',
SUCCEED_ON_FUNCTION_FAILURE = 'SUCCEED_ON_FUNCTION_FAILURE',
}

export enum Credentials {
Expand Down Expand Up @@ -52,6 +53,7 @@ const setAWSConfigOptions = () => {
AWS.config.maxRetries = parseInt(maxRetries, 10);
}
};

export const main = async () => {
try {
setAWSCredentials();
Expand All @@ -65,6 +67,15 @@ export const main = async () => {
const response = await lambda.invoke(params).promise();

setOutput('response', response);

const succeedOnFailure =
getInput(ExtraOptions.SUCCEED_ON_FUNCTION_FAILURE).toLowerCase() ===
'true';
if ('FunctionError' in response && !succeedOnFailure) {
throw new Error(
'Lambda invocation failed! See outputs.response for more information.'
);
}
} catch (error) {
setFailed(error.message);
}
Expand Down

0 comments on commit d3a63cc

Please sign in to comment.