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
Streamline from-browser initialization #3649
Streamline from-browser initialization #3649
Conversation
Codecov Report
@@ Coverage Diff @@
## main #3649 +/- ##
=======================================
Coverage 88.80% 88.80%
=======================================
Files 260 260
Lines 21736 21736
Branches 5566 5566
=======================================
Hits 19302 19302
Misses 2256 2256
Partials 178 178 Continue to review full report at Codecov.
|
af58c31
to
f15931d
Compare
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'd like to apology for the delay, because I wanted to have a clear mind to look at this complex code.
Thanks! This seems to work fine. But I think it would be a lot simpler if UrlManager
was creating the browserConnection, would there be a problem moving this creation and error handling there? I'm marking this PR with "request changes" for this reason.
Also I believe that this comment in UrlManager.js may need updating:
profiler/src/components/app/UrlManager.js
Lines 102 to 107 in 7a7fda0
// Also note the profile may be null for the `from-browser` dataSource since | |
// we do not `await` for retrieveProfileFromBrowser function, but also in | |
// case of fatal errors in the process of retrieving and processing a | |
// profile. To handle the latter case properly, we won't `pushState` if | |
// we're in a FATAL_ERROR state. | |
const profile = await retrieveProfileForRawUrl(window.location); |
The rest of this comment is fully optional, but I wanted to get your feedback on that.
I got this idea while looking at this patch and how we have to pass the browserConnection object around.
Instead of passing the browserConnection object everywhere (which I understand is because we don't want to reuse it so that the initialization is not run again, etc), we could make that a singleton, that would lazy-initialize at the first get, but then always return the same version of it.
One obvious drawback is that it would need a not very clean resetForTestsOnly
function. Or we could have a mock of BrowserConnection for most tests except the one testing that class only.
What do you think?
I'm not saying this is strictly better, and usually I don't really like keeping state if we can avoid it, but I feel like that this could reduce the complexity in this case, because you wouldn't need to return it everywhere just so that it's available at the right place.
Another option could be to set it in the redux state, then we could retrieve it in thunk actions (but this sounds like a hack to me, because we don't need it for rendering).
Thanks for reading!
Promise<{| | ||
profile: Profile | null, | ||
browserConnection: BrowserConnection | null, | ||
|}> |
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.
It doesn't feel very appropriate to return the browser connection from retrieveProfileForRawUrl
and retrieveProfileFromBrowser
just because we need it in the caller. This looks like more a side effect, a byproduct, of retrieving a profile.
What do you think of creating the browserConnection
in UrlManager
instead, and passing it to retrieveProfileForRawUrl
and then retrieveProfileFromBrowser
? Also UrlManager
looks like the right location to handle the errors related to the browser connection creation.
(I'm still thinking about removing the profile loading part of UrlManager and using ProfileLoader
at load time too, then ProfilerLoader
could keep all of this)
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 fully agree!
This is actually the next step I have in mind. See the "Call createBrowserConnection earlier." commit in #3656. It comes with a fair number of changes so I wanted to break it out into its own commit.
Thanks for the review!
Yes, definitely. I want to do it as a follow-up though.
Indeed! I missed that. For the rest of your comment, I have some notes about my opinions on it in #3656. Should we discuss it over there? Or maybe on Matrix / Zoom? |
With this change, retrieveProfileForRawUrl now always waits for the profile to be received, and calls loadProfile with initialLoad = true in all cases.
f15931d
to
106f7a7
Compare
I see, thanks for pointing to #3656. This looks like quite aligned with my own thoughts! I'll read this through and put my notes there. It feels a bit strange that you're implementing some things here that you rollback in the next commit of #3556 (especially returning the |
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.
approving following the previous comment
thanks, it's exciting to see all this work coming through!
Yeah exactly; it was a small step to the side in order to be able to delay two big steps forward. I wanted to keep this PR as small and focused as possible. |
If the initial URL is
/from-browser/
, profile loading goes a rather different path compared to/from-url/
and/public/
. This PR fixes that discrepancy.More in-depth description:
Symbolication happens in
finalizeProfileView
.finalizeProfileView
can only do symbolication with the help of the browser if it gets passed abrowserConnection
.finalizeProfileView
is called in two cases: For initial loads it's called fromsetupInitialUrlState
, and for non-initial loads it's called fromloadProfile
.Before this patch, the following was true:
setupInitialUrlState
didn't have abrowserConnection
, so it couldn't pass abrowserConnection
tofinalizeProfileView
. OnlyloadProfile
had abrowserConnection
that it could pass tofinalizeProfileView
.finalizeProfileView
had to be called fromloadProfile
, even during initial load.from-browser
had to passinitialLoad = false
even for the initial load - otherwiseloadProfile
wouldn't callfinalizeProfile
.from-browser
,finalizeProfileView
was always called twice during the initial load! First fromsetupInitialUrlState
, and then again fromloadProfile
.finalizeProfileView
did an early exit, because the call happened at a time when the profile in the redux state was still null.retrieveProfileForRawUrl
didn't awaitretrieveProfileFromBrowser
, sosetupInitialUrlState
was called before the profile had been obtained.initialLoad = false
forfrom-browser
: we were relying on that second call tofinalizeProfileView
(because the first call didn't do anything).After this patch, the following is true:
loadProfile
withinitialLoad = true
for all data sources now, including from-browser. SoloadProfile
no longer callsfinalizeProfile
during from-browser initial load. Now there is only one call tofinalizeProfile
: the one fromsetupInitialUrlState
.retrieveProfileForRawUrl
now awaitsretrieveProfileFromBrowser
. This means that the profile in the redux state is non-null oncesetupInitialUrlState
gets called.retrieveProfileFromBrowser
no longer includes symbolication, because we now call it withinitialLoad = true
, so itsloadProfile
call (which now getsinitialLoad = true
) doesn't callfinalizeProfileView
, which is what would kick off symbolication.retrieveProfileForRawUrl
now waits until the profile has been obtained, this also means that we now have a non-null profile at the point where we do URL upgrading even for from-browser. We don't really need that, but at least the code paths for the different data sources are now better aligned.setupInitialUrlState
now has thebrowserConnection
, so it can pass it along tofinalizeProfileView
, and symbolication works as expected.This PR also makes the following test fixes, to keep the tests passing:
retrieveProfileFromBrowser()
would time out waiting for the WebChannel. This function was already timing out during this test in the past, but we didn't notice it because nothing was waiting for that function to complete. The newawait
now putsretrieveProfileFromBrowser()
on the critical path for some of the tests in this file, so this situation needs to be rectified.PROFILE_LOADED
first and then callsfinalizeProfileView
in thefrom-browser
test, just like it's already doing in the/public/fakehash/
test. And since it now awaitsfinalizeProfileView
, it means that it waits for symbolication to complete, and needs to expect thatprofile.meta.symbolicated
istrue
.