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

fix: handle initialization errors on server.listen, handle fallback rejections #1227

Merged
merged 4 commits into from
Sep 22, 2021

Conversation

davidmurdoch
Copy link
Member

@davidmurdoch davidmurdoch commented Sep 22, 2021

fixes #938

This is a all weird because I want users to be able to do const provider = Ganache.provider()... notice there is no await here! 👀 Ganache.provider does approx 3,452,345 async things on start up though, and if any of these promises reject no one is there to listen to that rejection; so node complains (but doesn't crash in Node v10-14).

Unfortunately, this PR does not fix this problem for Ganache.provider(), but does fix it for Ganache.server() by having the server.listen function, which is async, handle promise rejections "eventually".

In order to get the provider to handle these errors we'd have to hook into the first async method the user calls after we have finished (failing) initialization... which would probably be something like await provider.request({method:"eth_accounts", params: []})... which is a weird place to throw an initialization error 😕.

blockLogs: null
});
({ stateRoot } = latest.header);
try {
Copy link
Member Author

Choose a reason for hiding this comment

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

this is just wrapping things in a try/catch

Comment on lines +262 to +263
await this.fallback.initialize();
await database.initialize();
Copy link
Member Author

Choose a reason for hiding this comment

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

This was changed because previously, if the fallback throws while database is still starting it becomes very tricky to ensure we can wait for the database to finish before trying to shut the blockchain class down. We can do it, and I did, but it was a lot of code involving handling the weird return values of Promise.allSettled combined with throwing an AggregateError in some cases and not in others.

// stop the polling miner, if necessary
clearTimeout(this.#timer);

// clean up listeners
this.vm.removeAllListeners();
this.vm && this.vm.removeAllListeners();
Copy link
Member Author

Choose a reason for hiding this comment

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

Since we now call stop internally on initialization exceptions we might not have everything ready, so we check for things' existence before trying to clean them up.

@@ -172,7 +172,7 @@ export class HttpHandler extends BaseHandler implements Handler {
if ("result" in result) {
return result.result;
} else if ("error" in result) {
throw result.error;
throw new CodedError(result.error.message, result.error.code);
Copy link
Member Author

Choose a reason for hiding this comment

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

don't throw plain objects, kids.

return {
connector,
promise: connectPromise.then(requestCoordinator.resume)
};
Copy link
Member Author

Choose a reason for hiding this comment

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

give connector loader callers, like server.ts, the ability to handle start up promise rejections.

// upgrading Typescript. TODO: if Typescript is upgraded to 4.2.3+
// then this line could be removed and `Promise.allSettled` below
// could replaced with `allSettled`.
allSettled.shim();
Copy link
Member Author

Choose a reason for hiding this comment

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

I just moved this block to the global scope.

// Since the ConnectorLoader starts an async promise that we intentionally
// don't await yet we keep the promise around for something else to handle
// later.
this.#initializer = Promise.all([
Copy link
Member Author

Choose a reason for hiding this comment

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

this promise is awaited in the listen function below, and that is where a Connector/Provider's initialization rejections will get handled now.

Copy link
Contributor

@MicaiahReid MicaiahReid left a comment

Choose a reason for hiding this comment

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

Added one clarification comment to your annotations.

@davidmurdoch davidmurdoch changed the title fix: handle connector/provider initialization errors on server.listen fix: handle initialization errors on server.listen, handle fallback rejections Sep 22, 2021
@davidmurdoch davidmurdoch merged commit 20a46cc into develop Sep 22, 2021
@davidmurdoch davidmurdoch deleted the fork-error-better branch September 22, 2021 15:30
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
2 participants