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

refactor(core): introduce cached lazies #11253

Merged
merged 7 commits into from
Nov 23, 2020
Merged

Conversation

rix0rrr
Copy link
Contributor

@rix0rrr rix0rrr commented Nov 2, 2020

Lazy.stringValue() used to be strictly uncached; however, this has an
extremely negative impact on synthesis performance when token resolution
is performed many times and complex operations are being performed in
Lazies, such as JSONification (see #11250 for context).

99% of the time, the value calculated by a Lazy does not actually
need to be recalculated, and the value can simply be cached. Right now,
we have no API to indicate whether or not caching on the return value is
okay.

Although it should probably be fine to switch the default behavior of
Lazy.stringValue() to be cached, it's still a little risky.

This PR introduces new methods to construct lazies:

  • Lazy.string()/Lazy.uncachedString().
  • Lazy.number()/Lazy.uncachedNumber().
  • Lazy.list()/Lazy.uncachedList().
  • Lazy.any()/Lazy.uncachedAny().

Which replace the existing Lazy.xxxValue().

New method names were chosen instead of an additional option for
readability: the syntactic structure of how Lazy.stringValue() is
usually used makes adding a { cached: true } options block to the end
of every existing call site rather visually noisy. Plus, deprecating the
existing method and replacing it with new ones forces current usage
sites to think clearly about whether or not their current use is
cacheable or not.

The very computationally heavy implemention of toJsonString() should
be changed to be cacheable, but has not been done yet in this PR. This
PR simply introduces the concept of cacheable vs uncacheable tokens.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

`Lazy.stringValue()` used to be strictly uncached; however, this has an
extremely negative impact on synthesis performance when token resolution
is performed many times and complex operations are being performed in
Lazies, such as JSONification (see #11250 for context).

99% of the time, the value calculated by a Lazy does not actually
need to be recalculated, and the value can simply be cached. Right now,
we have no API to indicate whether or not caching on the return value is
okay.

Although it should *probably* be fine to switch the default behavior of
`Lazy.stringValue()` to be cached, it's still a little risky.

This PR introduces new methods to construct lazies:

* `Lazy.string()`/`Lazy.uncachedString()`.
* `Lazy.number()`/`Lazy.uncachedNumber()`.
* `Lazy.list()`/`Lazy.uncachedList()`.
* `Lazy.any()`/`Lazy.uncachedAny()`.

Which replace the existing `Lazy.xxxValue()`.

New method names were chosen instead of an additional option for
readability: the syntactic structure of how `Lazy.stringValue()` is
usually used makes adding a `{ cached: true }` options block to the end
of every existing call site rather visually noisy. Plus, deprecating the
existing method and replacing it with new ones forces current usage
sites to think clearly about whether or not their current use is
cacheable or not.

The *very* computationally heavy implemention of `toJsonString()` should
be changed to be cacheable, but has not been done yet in this PR. This
PR simply introduces the concept of cacheable vs uncacheable tokens.
@rix0rrr rix0rrr requested a review from a team November 2, 2020 13:51
@gitpod-io
Copy link

gitpod-io bot commented Nov 2, 2020

@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Nov 2, 2020
Copy link
Contributor

@eladb eladb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't we concerned about using any, string, etc for method names (from a jsii perspective?).

Alternatively, you could use Lazy.toList(), Lazy.toAny(), ...

@rix0rrr
Copy link
Contributor Author

rix0rrr commented Nov 13, 2020

Aren't we concerned about using any, string, etc for method names (from a jsii perspective?).

I thought about it, but not really.

  • TypeScript: all good
  • Java: all good (there are no conflicting keywords)
  • C#: all good (string is a keyword but the method would be called String)
  • Python: all good (there are no conflicting keywords)
  • Go: all good (there are no conflicting keywords)

@rix0rrr rix0rrr requested review from eladb and a team November 13, 2020 17:12
Copy link
Contributor

@nija-at nija-at left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with the code changes themselves, save for the comments below.

Were you able to provide some data that this has the RoI you're looking for?
What kind of improvements is this giving? Is it worth the additional complexity and the extra API?

packages/@aws-cdk/core/lib/lazy.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/core/lib/lazy.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/core/lib/lazy.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/core/lib/lazy.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/core/test/tokens.test.ts Show resolved Hide resolved
* The inner function will only be invoked one time and cannot depend on
* resolution context.
*/
public static string(producer: IStableStringProducer, options: LazyStringValueOptions = {}) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't we concerned about using any, string, etc for method names (from a jsii perspective?).

Seems like a valid concern to me, although I see you've done the diligence of checking through our supported languages.

Would it be safe and maybe even clearer if we add preposition to it (asString or toString) indicating which type the Lazy will evaluate into?

I'm ok with leaving as-is if you feel strongly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, Lazy as String or Lazy to String don't make sense in my head. They imply a conversion, which is not what's happen. What's happening is construction of a new kind of value.

More appropriate would be any of:

  • Lazy.aString()
  • Lazy.newString()
  • Lazy.makeString()
  • Lazy.someString()
  • Lazy.stringLazy()
  • Lazy.lazyString()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your call here. I'm not fussed.

@rix0rrr
Copy link
Contributor Author

rix0rrr commented Nov 23, 2020

Were you able to provide some data that this has the RoI you're looking for?

This is not sufficient by itself. It also needs #11224 and #11254

@rix0rrr rix0rrr requested review from nija-at and a team November 23, 2020 14:51
@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject6AEA49D1-qxepHUsryhcu
  • Commit ID: 21e486b
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

Copy link
Contributor

@nija-at nija-at left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming there is value in building this additional caching. Would love to have seen some data, even anecdotal.

@mergify
Copy link
Contributor

mergify bot commented Nov 23, 2020

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@mergify mergify bot merged commit 9c5000d into master Nov 23, 2020
@mergify mergify bot deleted the huijbers/cached-lazies branch November 23, 2020 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants