-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Do a better job preventing serialization of unnecessary objects in closure serialization #1543
Conversation
…osure serialization.
// logInfo = logInfo || func.name === "addHandler"; | ||
if (logInfo) { | ||
console.log("Serializing " + func.name); | ||
} |
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 is effectively debug-only code. I end up adding this in a bunch, and i wouldn't mind just leaving this in. Note that it will not do anything by default since logInfo=undefined. But this allows for a pretty easy way to opt into turning on printf-style logging when helpful.
We could also consider some sort of logging library, but i didn't want to go through the pain of doing that.
serialize: (o: any) => boolean): FunctionInfo { | ||
serialize: (o: any) => boolean, logInfo?: boolean): FunctionInfo { | ||
|
||
// logInfo = logInfo || func.name === "addHandler"; |
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.
Useful for being able to turn on logging when serializing just a specific function.
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.
Should probably leave this out or formalize it as part of the debug logging for this package.
// if this property was invoked or not. | ||
for (const existingProp of combined) { | ||
if (existingProp.name === current.name) { | ||
existingProp.invoked = existingProp.invoked || current.invoked; |
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.
i removed this merging logic as it was too complex now that we have 'chains' of property-accesses recorded. Instead, now we just record all the chains, and we consider all of them (including dupes) when doing closure serialization. so if we have "a.b.c()" and "a.b.c" and "a.b.c", we'll record three chains of 'b.c' (with the first saying it is invoked). Then, in closure serialization, when we're emitting the value for 'c', we'll see if any of the accesses were 'invoked'.
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.
Couple notes. Generally this looks good - though there's a lot of subtle interactions here that are a little hard to track through. Glad to see the new tests!
Possibly @swgillespie can take a look as well.
serialize: (o: any) => boolean): FunctionInfo { | ||
serialize: (o: any) => boolean, logInfo?: boolean): FunctionInfo { | ||
|
||
// logInfo = logInfo || func.name === "addHandler"; |
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.
Should probably leave this out or formalize it as part of the debug logging for this package.
// validate our invariants. | ||
for (const chain of localCapturedPropertyChains) { | ||
if (chain.infos.length === 0) { | ||
throw new Error("We should never have gotten an empty chain."); |
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.
Nit: "Expected a non-empty chain." or similar.
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.
Done.
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.
I read through all of this but I need a little more time to fully digest it. I'll finish off the review first thing tomorrow.
context: Context, | ||
serialize: (o: any) => boolean): Entry { | ||
serialize: (o: any) => boolean, | ||
logInfo: boolean | undefined): Entry { |
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.
logInfo?: boolean
?
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.
I like forcing people to have to remember to call it. logInfo?:boolean
means it is optional, which means you might forget it.
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.
Does typescript not consider T | undefined
arguments to be optional?
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.
Alright, I got it now - LGTM! The comments were very helpful 😄
Serialize doNotCapture functions with a throwing function on the runtime side. This will help people get a reasonable error at runtime instead of just a null-ref.
I took a 3-pronged attack here:
|
I recommend reviewing https://github.com/pulumi/pulumi/pull/1543/files?w=1 as this will make the indentation changes tolerable.
I also recommend looking at parseFunction.ts first, then createClosure.ts.