Use async randomBytes API to speedup Windows startup #19242
Conversation
b14fab2
to
6829557
Compare
6829557
to
3fcdcde
Compare
This way we avoid delaying the opening of a project when reusing an existing Atom window.
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.
👍 LGTM
@@ -15,6 +15,7 @@ const path = require('path') | |||
const os = require('os') | |||
const net = require('net') | |||
const url = require('url') | |||
const {promisify} = require('util') |
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.
Oh hey! I didn't realize we had access to promisify
now. This will come in handy.
@@ -227,11 +230,16 @@ class AtomApplication extends EventEmitter { | |||
this.applicationMenu = new ApplicationMenu(this.version, this.autoUpdateManager) | |||
this.atomProtocolHandler = new AtomProtocolHandler(this.resourcePath, this.safeMode) | |||
|
|||
this.listenForArgumentsFromNewProcess() | |||
// Don't await for the following method to avoid delaying the opening of a new window. | |||
// (we await it just after opening 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.
👍 Excellent.
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.
Again, worth mentioning explicitly that this method is slow on Windows?
listenForArgumentsFromNewProcess () { | ||
if (!this.socketPath) return | ||
async listenForArgumentsFromNewProcess (options) { | ||
if (!options.test && !options.benchmark && !options.benchmarkTest) { |
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 still wish we had a more succinct way to express "a regular editor window" in these options. (Out of scope for this PR though.)
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 think it might be helpful to clarify the motivations behind not awaiting in comments. So just checking my understanding... this increases the window of time in which a race condition might exist, correct? I suppose there was always a small window anyway if you ran atom
twice quickly before the first Electron could start listening on the socket. This just makes it more likely.
Another question: Is there some way we can remember to revisit this when we upgrade Electron and see if crypto
is still so slow?
|
||
return socketSecret | ||
} | ||
|
||
const encryptOptions = (options, secret) => { | ||
const message = JSON.stringify(options) | ||
|
||
const initVector = crypto.randomBytes(16) | ||
// Even if the following IV is not cryptographically secure, there's a really good chance | ||
// it's going to be unique between executions which is the requirement for GCM. |
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 think it might be helpful to future readers if you explain the motivation for avoiding cryptographic randomness on this code path (that it's too slow).
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've added more explicit comments for both things in #19246
@@ -227,11 +230,16 @@ class AtomApplication extends EventEmitter { | |||
this.applicationMenu = new ApplicationMenu(this.version, this.autoUpdateManager) | |||
this.atomProtocolHandler = new AtomProtocolHandler(this.resourcePath, this.safeMode) | |||
|
|||
this.listenForArgumentsFromNewProcess() | |||
// Don't await for the following method to avoid delaying the opening of a new window. | |||
// (we await it just after opening 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.
Again, worth mentioning explicitly that this method is slow on Windows?
Exactly, it'll make this window (which is already a few hundred ms) unnoticeable longer in OSX/Linux (a few ticks) and quite much longer (up to a second) in Windows (at least until we upgrade to electron v3). I think that's a fair tradeoff, since the only side effect that this will cause is that two Atom windows will get opened under that situation.
Maybe we can use a specially-crafted comment that's easy to search on GitHub for the whole Atom org, and then we add a point to the electron upgrade manual doc (if it exists) to revisit all these messages whenever we upgrade the electron version? Something like: // TodoElectronIssue: `randomBytes` is slow on electron v2. This issue is fixed in v3. (I'm not using spaces/special characters since GitHub search is particularly bad when searching for non-words). |
In addition to what @rafeca suggested, we could also create a tracking issue for it and apply the |
Use async randomBytes API to speedup Windows startup
This PR changes a bit the logic of
atom-application
to make the authentication through sockets async, which fixes #19239.In order to make the code async and keep it as robust as possible a few changes needed to be done (basically to delay the execution of some logic while avoiding as much as possible potential race conditions).