-
Notifications
You must be signed in to change notification settings - Fork 317
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
Fixes for Error Handling #231
base: master
Are you sure you want to change the base?
Conversation
…ll be able to await the connectRetry.
formatting
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.
Thanks for the work on this! I've just left a couple of questions about why you chose to do a couple of things.
return false; | ||
} | ||
const statusCode = err.response.statusCode; | ||
const statusCode = err.response ? err.response.statusCode : err.body? err.body.status_code : 0; |
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.
What was the situation in which there was no err.response
but there was an err.body.status_code
? Has that come from the changes you made in NgrokClient
?
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.
From what I can tell, this doesn't come from changes to the NgrokClient. This change was made because I was receiving errors in the error handling that should have gone through the retry logic but didn't because of this problem.
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.
Given that one of the unit tests dealing with paid plans is broken now, it looks like this needs further investigation.
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.
The problem occurs when someone has a paid plan and it's in use on another machine. In other words, a tunnel cannot be created because only one tunnel is allowed.
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'd put this in a separate PR personally
src/client.js
Outdated
@@ -13,7 +13,7 @@ class NgrokClient { | |||
constructor(processUrl) { | |||
this.internalApi = got.extend({ | |||
prefixUrl: processUrl, | |||
retry: 0, | |||
retry: 3, |
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.
With retries from got
and retries based on the isRetriable
function we have two different ways that retries might happen. Is there a reason to include retries from got
specifically?
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.
Okay, makes sense to put this back to 0.
It seems that one of the tests is failing too. |
Yes, one test fails, I make a note of that in one of the comments. It think this needs further investigation. 👍
|
Do you reckon you can write a test for when the error handling was failing before, the error from #229? I am not sure what that that situation is, so it would help me understand that this fixes that, but also hopefully help me to fix the failing test under this pull request. |
I'm also hitting these errors @robblovell on a paid plan, let me know if you need help debugging together. |
If someone can provide a way to reproduce the error, I'd be happy to look into what is going on here too. I've just not seen this yet myself. |
heres how I was encountering the problem: main.js const ngrok = require("ngrok");
// ....
const ngrokUrl = await ngrok.connect({
addr: PORT,
authtoken: NGROK_AUTH_TOKEN,
region: "eu",
subdomain: NGROK_SUBDOMAIN,
});
package-json "start": "nodemon main.js" First time running Ngrok does what I expect but then when nodemon refreshes because of a code change in |
Thanks for that @zaccolley. I will try to reproduce that myself. I can suggest a workaround though, rather than have ngrok restart when nodemon restarts you can set up your project to start ngrok once and then have nodemon restart just the app and not the tunnel. Even once this is fixed, that is likely a better way to use the two modules together. |
That looks like the best way yeah, maybe it's a bit much to expect this library handle such quick closing of ngrok and recreating |
My guess right now, until I get some time for this, is that there's something going wrong with closing the process such that when it is started quickly again it is not ready and causes these unexpected errors. I do think that avoiding stopping and starting the process is likely better anyway though. |
I thought the same, |
I wonder if it's cause when we do a nodemon refresh we lose track of the current running ngrok process, and ngrok.kill is not going to do anything for that process at that point. |
My theory is that we need to listen for signals that get sent and kill the ngrok child process there and not during the "exit" event. The Node docs say that you cannot run asynchronous functions for the "exit" event. By default nodemon sends Being able to handle the signals and shutdown gracefully should mean that the processes don't get in a weird way and cause unexpected errors. |
Also, stop performing an asynchronous action on process exit. It is not officially supported. However subprocess.kill is not asynchronous, so can be used over the internal killProcess method. Fixes bubenshchykov#239. Should help bubenshchykov#231. Supersedes bubenshchykov#179
I think things might be simpler than having to catch all the different signals. On the |
Nice Phil, I think we should still fix the error handling in this PR as there could be another error that isn't caught in the future? |
@@ -28,20 +28,12 @@ class NgrokClient { | |||
} | |||
} catch (error) { | |||
let clientError; |
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.
Couple of things here:
- Now that we're not doing a
try ... catch
we don't need to create the variable at the start. - I think it is still worth catching errors from JSON.parse should the response body be incorrect JSON
- I think the double nested ternary statement makes it hard to follow the logic
- We repeat some logic that we can put in a helper function
Could we do something like this:
// .. defined above
function getResponse(error) {
if (error.response && error.response.body) {
let response;
try {
response = JSON.parse(error.response.body);
} catch (e) {
throw new NgrokClientError(e.msg, e.details);
}
return response;
}
return error;
}
// ... then
const response = getResponse(error);
throw new NgrokClientError(error.msg, error.details, response);
// ... and
} catch (e) {
const response = getResponse(e);
throw new NgrokClientError(e.msg, e.response, response);
}
I agree, if there's an issue in the error handling we should indeed fix it. Currently I have a couple of issues with this.
If we can fix the broken test and introduce at least a test case that this new code passes, then I'll be happy to merge. |
Errors in error handing appear to have broken the connect/retry logic. I have added some defensive measures that keep the error handling from crashing and now connect is more reliable.
fix #229
mightfix #222