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

Prevent lambda timeouts or failure from not handled promise due to invalid SSM parameter(s)... Add throwOnFailedCall flag to the SSM middleware #572

Merged
merged 2 commits into from
Nov 2, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/ssm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ npm install --save @middy/ssm
Defaults to `{ maxRetries: 6, retryDelayOptions: {base: 200} }`
- `setToContext` (boolean) (optional): This will assign parameters to the `context` object
of the function handler rather than to `process.env`. Defaults to `false`
- `throwOnFailedCall` (boolean) (optional): Defaults to `false`. Set it to `true` if you want your lambda to fail in case call to AWS SSM fails (parameters don't exist or internal error). It will only print error if parameters are not already cached.

NOTES:
* While you don't need _both_ `paths` and `names`, you do need at least one of them!
Expand Down
30 changes: 28 additions & 2 deletions packages/ssm/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ describe('🔒 SSM Middleware', () => {
})
})

test('It should throw error when some SSM params are invalid', async () => {
test('It should throw error when some SSM params are invalid and "throwOnFailedCall" flag is set to true', async () => {
await testScenario({
ssmMockResponse: {
InvalidParameters: ['invalid-smm-param-name', 'another-invalid-ssm-param']
Expand All @@ -301,7 +301,8 @@ describe('🔒 SSM Middleware', () => {
names: {
invalidParam: 'invalid-smm-param-name',
anotherInvalidParam: 'another-invalid-ssm-param'
}
},
throwOnFailedCall: true
},
callbacks: [
(error) => {
Expand All @@ -311,6 +312,31 @@ describe('🔒 SSM Middleware', () => {
})
})

test('It should resolve if "throwOnFailedCall" flag is not provided but some SSM params are invalid (will throw silently?)', async () => {
await testScenario({
ssmMockResponse: {
InvalidParameters: ['invalid-smm-param-name', 'another-invalid-ssm-param']
},
middlewareOptions: {
names: {
invalidParam: 'invalid-smm-param-name',
anotherInvalidParam: 'another-invalid-ssm-param'
},
throwOnFailedCall: false
},
callbacks: [
(_) => {
expect(_).toBeNull() // TODO: don't know how to test this properly... there is no mockObject to check whether was called or not! (Check if console.error prints '[Failed to get parameters from SSM] ...' ?)
},
() => {
expect(getParametersMock).toBeCalled()
expect(getParametersMock).toHaveBeenCalledTimes(2)
getParametersMock.mockClear()
}
]
})
})

test('It should not throw error when empty middleware params passed', async () => {
await testScenario({
ssmMockResponse: {},
Expand Down
1 change: 1 addition & 0 deletions packages/ssm/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface ISSMOptions {
paths?: { [key: string]: string; };
names?: { [key: string]: string; };
awsSdkOptions?: Partial<SSM.Types.ClientConfiguration>;
throwOnFailedCall?: boolean;
setToContext?: boolean;
paramsLoaded?: Boolean;
getParamNameFromPath?: (path: string, name: string, prefix: string) => string;
Expand Down
17 changes: 17 additions & 0 deletions packages/ssm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = opts => {
maxRetries: 6, // lowers a chance to hit service rate limits, default is 3
retryDelayOptions: { base: 200 }
},
throwOnFailedCall: false,
onChange: undefined,
paths: {},
names: {},
Expand Down Expand Up @@ -81,6 +82,22 @@ module.exports = opts => {
options.paramsCache = objectsToMap
options.paramsLoadedAt = new Date()
})
.catch(err => {
console.error(
'[Failed to get parameters from SSM] ',
err.message
)
// throw error if there is no params in cache already and flag throwOnFailedCall is provided
if (options.throwOnFailedCall && !options.paramsCache) {
throw err
}
// if we already have a cached params, then reset the timestamp so we don't
// keep retrying on every invocation which can cause performance problems
// when there's temporary problems with SSM
if (options.paramsCache) {
options.paramsLoadedAt = new Date()
}
})
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/ssm/package-lock.json

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