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

Migrate to "node2" debug engine #390

Merged
merged 14 commits into from
Feb 9, 2017
Merged

Migrate to "node2" debug engine #390

merged 14 commits into from
Feb 9, 2017

Conversation

vladimir-kotikov
Copy link
Contributor

@vladimir-kotikov vladimir-kotikov commented Feb 1, 2017

Use "node2" debugging engine (https://github.com/Microsoft/vscode-node-debug2) rather than "node" for debugging react-native code. As mentioned in #377 previous approach to debugging will be deprecated in Node 8.

This should resolve a lot of debugging issues we've seen previously, such as #367 and #356

Vladimir Kotikov added 6 commits January 31, 2017 16:26
- target es6 syntax as Chrome debug client seems to be targeting es6
- check for app worker's existence before disposing
- make sure packager port is known when handling attach request
- bail out properly
- use real path of node2 debugger package
- use raw NodeDebugSession to report error
- improve logging in app worker
@vladimir-kotikov
Copy link
Contributor Author

@MSLaguana, @roblourens I would really appreciate any feedback on this

// tslint:disable-next-line:align
const WORKER_BOOTSTRAP = `
// Hacks to avoid accessing unitialized variables
var onmessage=null, self=global;
Copy link
Member

Choose a reason for hiding this comment

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

Should you also reference importScripts here?

process.send(message);
};
importScripts = function(scriptUrl){
var scriptCode = require("fs").readFileSync(scriptUrl, "utf8");
Copy link
Member

Choose a reason for hiding this comment

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

I'm cautious about these requires here. I know that react-native redefines global require, so I'm not sure whether that can impact this if importScripts is called more than once. Might be worth using an IIFE to take a reference to the original require function initially and use that when importScripts is called? Or even just cache both fs and vm immediately and use those in importScripts

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great idea! I totally missed that fact with require override by react

// Before sending messages, make sure that the worker is loaded
this.workerLoaded.promise
.then(() => {
if (rnMessage.method !== "executeApplicationScript") return Q.resolve(rnMessage);
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't other messages be passed on to the other process to be run in there?

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I see that is handled in the done coming up next.

importScripts = function(scriptUrl){
var scriptCode = require("fs").readFileSync(scriptUrl, "utf8");
require("vm").runInThisContext(scriptCode, { filename: scriptUrl });
};`;
Copy link
Member

Choose a reason for hiding this comment

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

Something else that I would recommend is adding a global __debug__ object with a require function which caches the node require. This matches what we currently expose in the original sandboxing method, and allows things such as realm to provide shims for native functionality when necessary.

@roblourens
Copy link
Member

LGTM. You may want to follow this issue - microsoft/vscode#19650 - as we're talking about how the two debug adapters will interact in the future. It probably won't mean anything for you, at least for February. There's a chance they could end up merged into a single extension or something, but probably not.

@MSLaguana
Copy link
Member

On the whole this looks pretty good to me. Am I correct that the SingleLifetimeAppWorker is no longer used at all, and is replaced by the forking app worker?

@vladimir-kotikov
Copy link
Contributor Author

vladimir-kotikov commented Feb 2, 2017

Thanks for review, guys!

Am I correct that the SingleLifetimeAppWorker is no longer used at all, and is replaced by the forking app worker?

That's correct. I initially thought that we might want to keep them both, just in case if we plan to support old "node" debugger, but this doesn't seem to be the case. Am i right? Do you want me to drop that old worker code?

function killWorker(worker: IDebuggeeWorker) {
if (!worker) return;
worker.stop();
worker = null;
Copy link
Member

Choose a reason for hiding this comment

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

This won't modify this.worker which I believe was your intent.

@MSLaguana
Copy link
Member

Looks like one of our tests is failing now, but it seems to be specifically to do with the single lifetime worker which isn't as relevant any more. Could you please look into that and update or remove the test as appropriate?

@MSLaguana
Copy link
Member

Also to answer your question about the single lifetime worker: I think it would be best to only have the one way of doing things, so I am inclined to remove the single lifetime worker and just focus on the forked worker.

Vladimir Kotikov added 5 commits February 3, 2017 18:21
Worker script needs to be downloaded from packager and patched only once. However it was downloaded every time when new SingleLifetime worker was starting. Moving the download logic to MultipleLifetime worker would improve reload time.

Also extract worker downloading logic for better testability
@vladimir-kotikov
Copy link
Contributor Author

@MSLaguana, addressed your comments and updated tests to actually test current worker implementation. Please take a look once more

});

test("should be able to import scripts", function() {
const scriptImportPath = "testScript.js";
// NOTE: we're not able to mock out
Copy link
Member

Choose a reason for hiding this comment

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

Looks like this comment is unfinished?

Copy link
Contributor Author

@vladimir-kotikov vladimir-kotikov Feb 9, 2017

Choose a reason for hiding this comment

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

Yeah, there should be a reasoning why we have to use real script file to test importScripts. I'll update.

// We have not yet finished importing the script, we should not have posted a response yet
assert(postReplyFunction.notCalled, "postReplyFuncton called before scripts imported");
scriptImportDeferred.resolve(void 0);
return Q.delay(1);
return Q.delay(100);
Copy link
Member

Choose a reason for hiding this comment

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

What's the reasoning behind increasing this limit here? Before we used 1 just to make sure that it was asynchronous. Is the delay of 100ms actually required for processing to happen on time, are there potential race conditions here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that previously the timeout was required just to delay dispatching the current promise chain and let scriptImportDeferred chain to be dispatched first.

In this implementation the spawned process is a black box and completely async for us so we can't reliably determine when the script has been imported and executed, so the only way to test this IMO is to give some reasonable amount of time to worker to complete script's import before checking if it has been done.

As for race conditions - not sure where are they might happen. Every test spawns it's own worker, so they are isolated from each other.

@MSLaguana
Copy link
Member

Just a couple of questions, looking good.

@MSLaguana
Copy link
Member

Looks great, thanks @vladimir-kotikov!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants