Skip to content
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

[Refactor Flask III] Remove api.abort and other error handlers #798

Merged
merged 37 commits into from
May 29, 2024

Conversation

CodyCBakerPhD
Copy link
Collaborator

@CodyCBakerPhD CodyCBakerPhD commented May 25, 2024

Assessing how much of the previous logic around api.abort or api.errorhandler is actually necessary with the new logger structure attached to the app

The following are two example logs that also printed messages to the dev console

The were both triggered by the temporary/fake NotImplementedError places in the dataset generation endpoint and triggered via the 'generate' button on the settings page

The first, (31) did not have the api.abort

2024-05-25_17-14-31.log

It also corresponds to this screenshot of the displayed error on the GUIDE

image

The second (32) used the possibly temporary decorator which has basically the same effect as the old try/except

2024-05-25_17-13-32.log

Its screenshot of the displayed error was

image

Furthermore, removing the api.errorhandler changed nothing in either case for either the displayed message, dev console, or log

Conclusion: I'd say we no longer need any api.abort or other error handling now that we have the core logger

@garrettmflynn WDYT?

Base automatically changed from test_simple to main May 27, 2024 15:39
@garrettmflynn
Copy link
Member

This seems fine. The request now directly throws an error on the GUIDE in a way that keeps the Error type appended to the front of the message—though I don't mind that too much. Can always parse it out if desired

@garrettmflynn
Copy link
Member

And this decision seems a bit simpler, where we remove any parsing from the backend and move it to the frontend

@CodyCBakerPhD
Copy link
Collaborator Author

From @garrettmflynn in #796 (comment)

Ah gotcha. There are no serious issues with changing the error handling to (a), though I'd keep an eye on the error messages to ensure they are still formatted as expected. If anything, this change should result in "harder" errors—in the sense that triggering an endpoint with the fetch API will error directly instead of requiring some JavaScript-side error detection on a "successful" message back.

See src/electron/renderer/src/stories/pages/guided-mode/options/utils.js line 90 for an example of this that is no longer triggered when the generate data endpoint is called.

And how does

).catch((error) => {
this.notify(error.message, "error");
throw error;
});
interact with
if (results?.message) throw new Error(`Request to ${url} failed: ${results.message}`);
?

All I know right now is that a good looking error is notified to the front end

@CodyCBakerPhD CodyCBakerPhD changed the title [Refactor Flask II] Assess api.abort and other error handlers [Refactor Flask ??] Assess api.abort and other error handlers May 27, 2024
@garrettmflynn
Copy link
Member

From @garrettmflynn in #796 (comment)

Ah gotcha. There are no serious issues with changing the error handling to (a), though I'd keep an eye on the error messages to ensure they are still formatted as expected. If anything, this change should result in "harder" errors—in the sense that triggering an endpoint with the fetch API will error directly instead of requiring some JavaScript-side error detection on a "successful" message back.

See src/electron/renderer/src/stories/pages/guided-mode/options/utils.js line 90 for an example of this that is no longer triggered when the generate data endpoint is called.

And how does

).catch((error) => {
this.notify(error.message, "error");
throw error;
});

interact with

if (results?.message) throw new Error(`Request to ${url} failed: ${results.message}`);

?
All I know right now is that a good looking error is notified to the front end

The catch statement "catches" any errors happening in the asynchronous function above it. So previously I needed to manually throw the failure message returned from the endpoint—but now the fetch command itself is throwing the error.

@CodyCBakerPhD
Copy link
Collaborator Author

The catch statement "catches" any errors happening in the asynchronous function above it. So previously I needed to manually throw the failure message returned from the endpoint—but now the fetch command itself is throwing the error.

So does that make the frontend simpler? We can still catch the fetch right? So we don't need the extra line in run to manually throw the Error?

@garrettmflynn
Copy link
Member

Yes, since the error handling is uniform now, I believe we can rely on the native error thrown across all requests.

@CodyCBakerPhD CodyCBakerPhD changed the base branch from main to break_up_endpoints May 28, 2024 03:40
@CodyCBakerPhD CodyCBakerPhD changed the title [Refactor Flask ??] Assess api.abort and other error handlers [Refactor Flask III] Assess api.abort and other error handlers May 28, 2024
@CodyCBakerPhD CodyCBakerPhD changed the title [Refactor Flask III] Assess api.abort and other error handlers [Refactor Flask III] Remove api.abort and other error handlers May 28, 2024
@CodyCBakerPhD
Copy link
Collaborator Author

OK I removed all the places I could spot

Be sure to play around with this in the app to ensure it behaves as we both expect

@garrettmflynn
Copy link
Member

It seems like the behavior has changed markedly since my last test.

Source Data Error

Is this sufficient for us? The entire error is still visible in the console and log file.
Screenshot 2024-05-28 at 7 55 06 AM

This can be triggered by specifying an incorrect path for the Phy interface.

Arbitrary Data Generation Error

Now when I raise a NotImplementedError in the dataset generation resource, the endpoint passes without triggering an error—despite being caught as a 500 error on the backend
Screenshot 2024-05-28 at 7 58 16 AM
Screenshot 2024-05-28 at 7 57 07 AM

If I re-support the manual error thrown when detecting result.message in the run function, this will pass—though the error received will be the same minimally informative Internal Server Error as the previous case.

@garrettmflynn
Copy link
Member

garrettmflynn commented May 28, 2024

Not sure where the difference between the two is. I can reinstate a robust error statement for both cases by adding an error handler to the main API for the Flask app—though this requires the old request.message check, albeit only for the data generation call...

Screenshot 2024-05-28 at 8 21 29 AM Screenshot 2024-05-28 at 8 20 23 AM

@garrettmflynn
Copy link
Member

Ah figured it out. These are not actually handled differently by the backend. Instead, the frontend calls are different.

For the metadata request, I'm using a raw fetch request on the SourceData page and parsing the result.message value in a custom way to show a portion of the traceback (which is not usually shown).

Sitting down for the week, I remember that I've had a bit of a gripe with the way fetch and Flask endpoints interact across all my current applications, as the native catch is rarely thrown. Instead, you have to parse the error out of a "correct" response if you'd like to handle it in a custom way. Even if you're using the default error-catching system (as seen in how the message was handled in the first comment, which I now realize did parse result.message).

So it seems like we will need to keep the frontend aspects of this parsing. And it might be a good idea to include a top-level exception handler to ensure we receive errors that can be formatted in an informative way.

Thoughts?

@garrettmflynn
Copy link
Member

You got it. I've already pushed it in a comment for comparison.

@CodyCBakerPhD
Copy link
Collaborator Author

@garrettmflynn Does my latest push satisfy the issues? Restructured the message to match Python more closely

@garrettmflynn
Copy link
Member

Not quite. Seems like both of the previous test errors (i.e. NotImplementedError in the data.py endpoint, as well as an incorrect Phy folder_path) don't actually have a type returned.
Screenshot 2024-05-28 at 2 00 08 PM
Screenshot 2024-05-28 at 1 58 06 PM

@CodyCBakerPhD
Copy link
Collaborator Author

Not quite. Seems like both of the previous test errors (i.e. NotImplementedError in the data.py endpoint, as well as an incorrect Phy folder_path) don't actually have a type returned.

My bad, f-string for the message was botched

Can you try again?

Frontend is just displaying the message right? And traceback gets console.log'ed?

@garrettmflynn
Copy link
Member

Just a bit different than that. The frontend adds a small amount of formatting as shown here (after updating the error handler to pass back the type and message separately).

Screenshot 2024-05-28 at 3 29 46 PM

I removed the traceback, as that's shown by forwarding the stdout to the Electron window. Was relevant for showing a certain code snippet that was returned from one of the source data failures—but it adds an edge-case to handle for something that doesn't happen very often.

@CodyCBakerPhD CodyCBakerPhD marked this pull request as ready for review May 29, 2024 16:28
@CodyCBakerPhD CodyCBakerPhD self-assigned this May 29, 2024
@CodyCBakerPhD CodyCBakerPhD enabled auto-merge May 29, 2024 17:02
Copy link
Member

@garrettmflynn garrettmflynn left a comment

Choose a reason for hiding this comment

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

Looks great. Thanks for pushing on this!

@CodyCBakerPhD CodyCBakerPhD merged commit b72a15a into main May 29, 2024
21 checks passed
@CodyCBakerPhD CodyCBakerPhD deleted the swap_try_except_to_decorator branch May 29, 2024 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants