Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Run each console command in its own child process #3255

Merged
merged 20 commits into from
Aug 25, 2020
Merged

Conversation

fainashalts
Copy link
Contributor

@fainashalts fainashalts commented Aug 13, 2020

This PR runs commands from inside the truffle develop and truffle console command processes. While this PR changes the way truffle develop and truffle console work under the hood, the end user CLI experience should not be different.

These changes became necessary when we found that Node v12 does not allow UncaughtException listeners in a REPL within another NodeJS program, and that one of our dependencies uses such a listener. By running a separate REPL in a child process we are able to bypass this problem. The issue that brought this to our attention is here: #2463

In the process of this work, it became apparent that the ReplManager class we had been using to manage multiple REPLs was no longer necessary since each REPL will now be in its own process. This PR thus also removes the repl.js file and directly accesses the node REPL as needed in console.js and interpreter.js.

To test this PR, run either truffle develop or truffle console and then use these to test out any other Truffle commands that make sense: migrate --reset, compile, test, debug, etc. Everything should work as it did previously, with the exception that the --network flag will throw an error when used with truffle develop -- the only network that should be used by truffle develop is the develop network.

Comment on lines +154 to +159
try {
this.provision();
} catch (e) {
console.log(e);
}
} catch (err) {
callback(err);
}
Copy link
Member

Choose a reason for hiding this comment

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

Is the intention to eat exceptions thrown by this.provision() and not invoke the callback on 160?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unless I'm misunderstanding, the callback on lime 160 is for any exceptions thrown by spawning the repl. There's a try/catch for this.provision() and a try/catch for the spawning. Does that make sense or am I not following?

Copy link
Member

Choose a reason for hiding this comment

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

The intention is a bit hard to follow because the two catch expressions are next to each other. As it exists, if the provision after spawn fails then the code explicitly eats the error and continues execution to the next REPL prompt. Is an exception thrown by this.provision() benign as the code suggests?

Copy link
Member

Choose a reason for hiding this comment

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

this.provision(); can throw an Error (line 110) if something is awry with an artifact file. I think we should be invoke the callback in the outer catch block.

@gnidan
Copy link
Contributor

gnidan commented Aug 16, 2020

Hey @fainashalts, check out the bundled version of Truffle - there's a deprecation notice upon every child process:

truffle(develop)> test
(node:96195) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
Using network 'develop'.

(On Node v10.22)

Copy link
Contributor

@gnidan gnidan left a comment

Choose a reason for hiding this comment

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

Few more comments for you @fainashalts.

packages/core/lib/console.js Outdated Show resolved Hide resolved
packages/core/lib/debug/interpreter.js Show resolved Hide resolved
Copy link
Contributor

@gnidan gnidan left a comment

Choose a reason for hiding this comment

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

Marking this as "request changes" until we can resolve that Buffer() error (or at least get to the bottom of it!)

const Web3 = require("web3");

const inputStrings = process.argv[2];
const network = process.argv[3];
Copy link
Contributor

@gnidan gnidan Aug 20, 2020

Choose a reason for hiding this comment

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

Can we merge these two? i.e., if the user runs debug --network mainnet from inside truffle console --network development, then I would expect the debug command to connect to mainnet. This implementation suggests that behavior might be undefined (or favor the network specified by process.argv[3])

Seems like we shouldn't pass network separately as a positional argument, and instead pass it as a named --network option. Two options come to mind for how to do that:

  1. Add logic to the parent process to merge --network=<network-name> into inputStrings, possibly by decoding inputStrings into a mapping + then re-encoding with { network } merged in.

  2. Use a -- separator between parent-process-provided options and user-provided options, e.g.:

truffle(develop)> debug <tx-hash> --fetch-external
   ... would run command:
   $ console-child.js --network=develop -- debug <tx-hash> --fetch-external
          from parent ^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ from user

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @gnidan so I don't think it's necessary to make this change - as far as I can tell, passing debug --network mainnet does run debug on mainnet even if truffle console was passed a different network. I tested with truffle console --network development and then debug <txhash> --network test, which I had running on a different port. The behavior is as expected. Let me know if that's not sufficient or if I'm missing something.

I'm actually not passing network to the run process, just in order to do a Config.detect() in order to get the develop network set up for the ganache url we pass to set up the provider (I know it's a separate consideration re: the hardcoded develop logic, which we've decided to address separately I believe).

If this is more of a concern re: having network as a positional argument from the parent, I can do a merge but it sort of seems unnecessary to me? Let me know what you think, thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @gnidan! #3296 addresses this in case you do want to get rid of the positional argument. Wanted to save you a little time!

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks so much @fainashalts, thanks for knocking that out!

That PR looks great! But why is it failing ☹️ ? (Re-running now)

@gnidan gnidan changed the title Spawn repl Run each console command in its own child process Aug 24, 2020
Copy link
Contributor

@gnidan gnidan left a comment

Choose a reason for hiding this comment

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

I think this is good to go!

@eggplantzzz I think when you do the release this week, you should enlist a bunch of us to participate in smoke-testing to give this the extra diligence it needs.

@fainashalts fainashalts merged commit e5cfd95 into develop Aug 25, 2020
@fainashalts fainashalts deleted the spawn-repl branch August 25, 2020 22:44
@fainashalts fainashalts restored the spawn-repl branch August 27, 2020 02:00
@haltman-at haltman-at deleted the spawn-repl branch June 26, 2023 19:05
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants