-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Issue 3821: Only request CloudFormation variables once #4294
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
Issue 3821: Only request CloudFormation variables once #4294
Conversation
…he same promise for subsequent requests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Despite of the lodash and simplification switches, I'm not really sure if this approach is the right solution for the problem, as the promises are cached. Imo the problem should be solved a level higher, so that variable values are cached, and not their fetching promises.
The whole problem does not only affect CF vars (although the symptom becomes visible with them) and we should fix the root of the problem and not the symptoms.
lib/classes/Variables.js
Outdated
if (!this.cfVars[stackName]) { | ||
this.cfVars[stackName] = {}; | ||
} | ||
this.cfVars[stackName][outputLogicalId] = promise; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole if/if can be turned into a single line with lodash:
_.set(cfVars, `${stackName}${outputLogicalId}`, promise);
This will automatically create all needed path objects if they do not exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for that. You may have guessed I am very new to javascript :)
lib/classes/Variables.js
Outdated
this.cfVars[stackName] && | ||
this.cfVars[stackName][outputLogicalId] | ||
) { | ||
return this.cfVars[stackName][outputLogicalId]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should return a promised value here as the function's current signature also returns promises.
return BbPromise.resolve(this.cfVars[stackName][outputLogicalId]);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cached values are promises so I don't think this is needed.
lib/classes/Variables.js
Outdated
this.cfVars && | ||
this.cfVars[stackName] && | ||
this.cfVars[stackName][outputLogicalId] | ||
) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be simplified with lodash:
const cachedVar = _.get(this, `cfVars.${stackName}.${outputLogicalId}`);
if (cachedVar) ...
I initially looked at caching the values themselves instead of the promises but it seemed to me that the code changes required to do this would have been more significant and I wasn't confident I could do it quickly and safely. Whilst I agree that this is just fixing a symptom I imagine that fixing the underlying problem is a lot more work and this at least allowed me to continue using the CF vars. |
I'll remove the "closes" comment in the issue to prevent the issue to disappear. I'm fine with having this as ad-hoc hotfix, so that it is usable again. The only thing that's missing right now here is, to add a unit tests that checks that the cache is function (by having a test variable solution that loads multiple variables multiple times and check if the retrieval itself is only called once). |
We have a new PR #4499 that is the first part of the solution and introduces a generic caching as first step. The AWS specific request optimization and caching should be done within I'll close this one in favor of the other. |
What did you implement:
When requesting CloudFormation variables first check if there has already been a request for the same variable and if so return the promise from the first request.
Hotfix for #3821
How did you implement it:
Store the AWS request promises in an instance variable map keyed by stack and variable name. Check the map before going to AWS.
How can we verify it:
To check this, create multiple variables in the serverless.yml all referring to the same CloudFormation variable. e.g.:
Only one call should be made to AWS.
Todos:
Is this ready for review?: YES
Is it a breaking change?: NO