-
Notifications
You must be signed in to change notification settings - Fork 406
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
Handle AbortError if fetch is cancelled in-flight #490
base: master
Are you sure you want to change the base?
Conversation
I'm going to test this out tomorrow in my app since it doesn't seem like there are any automated tests for the Javascript code. |
Maybe we re-throw instead of logging for I am still somewhat confused at how calling a non patched "fetch" works given that the promise would be aborted. |
This is my understanding of the situation, but I am also new to using In my application code, I have something like this: export default class extends Controller {
connect() {
this.controller = new AbortController();
}
show() {
const { signal } = this.controller;
fetch("/some/endpoint", { signal })
.then(r => r.text())
.then(html => {
// do some stuff
console.log(html);
})
.catch(() => {});
}
hide() {
this.controller.abort();
}
} If we But the profiler has patched fetch("/some/endpoint", { signal })
.then(r => r.text())
.then(html => {
// do some stuff
console.log(html);
})
.catch(() => {})
.then(response => {
// do the rack-mini-profiler stuff since the response is finished
}) Since the additional |
Codecov Report
@@ Coverage Diff @@
## master #490 +/- ##
=======================================
Coverage 88.64% 88.64%
=======================================
Files 18 18
Lines 1250 1250
=======================================
Hits 1108 1108
Misses 142 142 Continue to review full report at Codecov.
|
This is where I am getting really confused: From my reading of this code it should be running:
Something about the implementation in mini profiler does not feel right, maybe we should refactor this code a bit so it is clearer, this giant try catch nest is not that easy to understand. |
Ah, I think you are right and maybe this https://github.com/MiniProfiler/rack-mini-profiler/blob/master/lib/html/includes.js#L983-L985 is actually where the edit: I think I am now equally confused! If the request is aborted then it should not even get into the patched |
After more testing, I think we were both wrong. The Promise chain "forks" since RMP returns the original This makes sense because even when I was getting the unhandled exceptions, my app was still working correctly.
So whatever my application code does has no bearing on the exception handling in the profiler (and vice-versa). I think the original solution then would be best: the profiler will need to shallow the AbortError to avoid to extra noise in JS error tracker and confusion when developing. The PR as it currently exists seems good to me and resolves my issue after testing. |
Just lost 3 hours debugging this until I found that the mini-profiler monkey-patches |
We also spent way too much time trying to figure out why this error was appearing in our error tracker. Any chance of getting this merged? |
I just stumbled onto this as well, seeing "Uncaught (in promise)" in my browser logs when I have a What @swanson says about the promise chain "forking" seems to make sense to explain why I'm seeing errors, with the stacktrace pointing back to RMP. But I wonder, should RMP only swallow the For example, running this code (assuming you have nothing listening/responding locally on port 1234, simulating a non-abort error), trying to demonstrate the separate chains: const f = fetch('http://127.0.0.1:1234');
// RMP
f.then(() => {});
// Application
f.catch(() => console.log('caught from application')); You'll see you get the "caught from application" log line, as handled by the application, but you'll also get the "Uncaught (in promise)" error, as if both chains are acting independently. If you change the RMP line to f.then(() => {}).catch(() => {}); You'll still get the "caught from application" log line, so that side didn't break, but you no longer get the "Uncaught (in promise)" error on the RMP side. Best I can tell, the order doesn't matter, so whether the RMP chain is set up first, or the application chain, the result is the same. Just for kicks, if you remove the RMP and application chains and replace it with a single chain (simulating @SamSaffron's assumption earlier of appending rather than forking): f.then(() => {}).then(() => {}).catch(() => console.log('caught from application')); You'll get the "caught from application" line, and no "Uncaught (in promise)" line, but since RMP returns the result of I only tested this in Chrome (v131.0.6778.205), but hopefully this behavior is true across browsers. I'm also far from an expert on promises, so take this all with a grain of salt. Alternatively, maybe RMP should be returning the chain after |
Resolves #489
Per guidance here: https://developers.google.com/web/updates/2017/09/abortable-fetch#reacting_to_an_aborted_fetch
Users may choose how to handle the rejected promise in their own code, but the profiler will not raise an uncaught exception.