The `meteor debug` command behaves like Node's `--inspect-brk` flag, in
that it attempts to pause the server before executing any server code.
However, simply passing the `--inspect-brk` flag to Node causes execution
to pause on the very first line of code, which is not good for setting any
breakpoints, because no server code has actually loaded yet.
Instead, the `meteor debug` command uses Node's `--inspect` flag to enable
debugging without an initial pause, then manually pauses at an appropriate
moment during server startup. Ideally, the pause should last until an
inspector client has been attached to the process, at which point the
developer has a chance to set any desired breakpoints, then clicks the
continue button to proceed with server startup.
The most difficult part of this process is detecting when the inspector
client has attached. Previously, the parent process listened for the child
process to print a "Debugger attached" message to STDERR, which happens as
a result of this `fprintf` call in Native C++:
7cff6e80bf/src/inspector_io.cc (L396)
However, this message was not printed in some cases, especially on Windows
(#9165), and required inter-process communication even in the ideal case.
All of that logic is gone now, thanks to this commit.
This commit takes advantage of a difference in behavior of the `debugger`
keyword depending on whether or not an inspector client is attached. When
no client is attached, the `debugger` keyword is a no-op that takes no
time (or very little time) to execute. Once a client has attached, the
`debugger` keyword triggers a breakpoint that lasts until the developer
explicitly continues execution through the client UI. Needless to say,
this makes the `debugger` keyword take longer than a no-op.
Because the `debugger` keyword does nothing until a client connects, we
can safely poll a `pause` function containing a `debugger` keyword at a
frequent interval (say, every 500ms). Once a client connects, the
`debugger` keyword will become active, pausing the server at exactly the
point we hoped. The difference is easy to detect by timing the `pause()`
function call. Once the `debugger` keyword becomes active, we stop polling
and allow server startup to continue.
Elegant!
Fixes#9165.
This is the feature that excites me most about Meteor 1.6, hands down.
Benefits include:
* Works with `meteor test[-packages] --debug-port 9229` (for tests), as
well as just `meteor debug` (for apps).
* The application process waits patiently for the debugger to attach, so
you don't have to race to open the debugger.
* The application process pauses at a location just after all server code
has been evaluated, but before any code starts executing, giving you a
chance to set reliable breakpoints anywhere in server code. This is much
better than using the `node --inspect-brk` flag, since that stops too
soon to set any useful breakpoints.
* The application server runs at full speed, so you don't have to wait
forever to hit that all-important breakpoint, and you don't lose nearly
as much time if you accidentally continue past the line of code where
the trouble is occurring.
* Even if your application is stuck in an infinite loop, you can still
attach the debugger, pause execution, and debug the loop.
* No more `node-inspector`! Instead, you can now debug your server code in
native Chrome DevTools, or several other high-quality inspector clients,
such as VS Code or WebStorm (seriously, check out the documentation:
https://nodejs.org/en/docs/inspector/#inspector-tools-clients). The list
of debuggable processes can be found at the URL chrome://inspect.
* Realistic performance and memory profiling is now possible via the
familiar DevTools interface.
* I highly recommend this Chrome extension that automatically (re)connects
to any open inspector sockets, so you don't have to keep manually
(re)attaching the debugger: http://june07.com/nim
* The implementation of `meteor debug` no longer has to proxy multiple
private/public debugger ports. Look at all that deleted code!
This new inspector is so much better than the old `node-inspector` that
I've been using the release-1.6 branch to debug problems in Meteor 1.5,
despite the risks of using Node 8, because those risks are so far
outweighed by the quality of the new debugging experience.
That said, the experience isn't perfect (yet). I welcome your feedback on
the Meteor 1.6 PR: https://github.com/meteor/meteor/pull/8728