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

Fixes the missing exception throw action when an api request is executed, like BucketExistsAsync, etc. #1141

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

ebozduman
Copy link
Collaborator

@ebozduman ebozduman commented Jul 24, 2024

Fixes #1118
and probably #1114, #1121, #1131 and #1132, ....
There may be some more issues filed for this very same issue.
If I find more, I'll add them here.
#1120 (The PR that tried to fix the issue)

@ebozduman ebozduman force-pushed the swallowed-exceptions-when-server-down branch from 50b3c03 to 72b2b07 Compare July 24, 2024 23:29
@ebozduman ebozduman changed the title Resolves the wrong return value of BucketExistsAsync api Fixes the missing the exception throw when an api request is executed, like BucketExistsAsync Jul 25, 2024
@ebozduman ebozduman changed the title Fixes the missing the exception throw when an api request is executed, like BucketExistsAsync Fixes the missing exception throw action when an api request is executed, like BucketExistsAsync, etc. Jul 25, 2024
Copy link
Contributor

@ramondeklein ramondeklein left a comment

Choose a reason for hiding this comment

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

I can't really sign off on this. Code can be simplified, but even if you do, this core method changes semantics significantly and may have serious impact on API usage. Instead of returning an error response, this throws an exception instead.

throw;
}

responseResult = new ResponseResult(request, ex);
Copy link
Contributor

Choose a reason for hiding this comment

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

This code will never be executed. Because responseResult is set at line 93, the previous if statement will always be true and the exception will be rethrown.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done!

responseResult.Exception = ex;
else
responseResult = new ResponseResult(request, ex);
throw;
Copy link
Contributor

Choose a reason for hiding this comment

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

It makes no sense to set responseResult.Exception in the previous line and now rethrow the exception. The caller of this function will never receive the responseResult.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

removed!

Copy link
Contributor

Choose a reason for hiding this comment

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

All code from lines 147-155 can be replaced by throw; and you would have had the same functionality as you implemented right now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done!

@rhegner
Copy link

rhegner commented Jul 25, 2024

@ebozduman even with your suggested changes, that entire error handling does not look very trustworthy to me.

@ramondeklein already mentioned some issues.

I didn't dig very deep in the code base, but it seems to me that the root cause of all the evil is that there is a mix of throwing exceptions and returning (unthrown) exception objects within the ResponseResult. For example, with your latest code change, in most cases exception are (re-)thrown. But if the responseResult variable is null in line 147, the exception will not be thrown, but instead returned. The fact that these two approaches are mixed, makes understanding (and maintaining) the entire error handling logic pretty difficult and fragile. [The fact that error handling is broken in various ways across multiple versions of the library is the best proof for that.]

My suggestion would be this (again, I don't really know the code base, so I might miss something):
Remove the Exception field in ResponseResult completely and transport exceptions only by throwing them. I think this would streamline the entire exception handling logic (and I think the required changes are limited to only a small part of the codebase).


Additional thoughts:

I could imagine that the original rationale for transporting exceptions inside of ResponseResult instead of throwing was to facilitate the idea of invoking "error handlers".
BUT: That mechanism seems to be broken anyways, see HandleIfErrorResponse method. If there is an exception, the method throws in line 386, so the handlers will never be invoked in line 391.

So, again, I think the entire error handling needs simplification and streamlining. Let all exceptions throw. If you want to keep the concept of error handlers, invoke them from within a catch block in an appropriate place, and then re-throw.

@COCPORN
Copy link

COCPORN commented Jul 27, 2024

Just merge the obvious fix.

This is embarrassing.

@rhegner
Copy link

rhegner commented Jul 29, 2024

@ebozduman these are the results of my testbench:

// Minio Version                                6.0.0   6.0.1   6.0.2   6.0.3   PR
// ------------------------------------------------------------------------------------------------
await TestExistsWithExistingObject();       //  ok      ok      ok      ok      ok
await TestExistsWithNonexistingObject();    //  ok      NOK     ok      ok      ok
await TestExistsFromInvalidEndpoint();      //  ok      ok      NOK     NOK     different exception
await TestDownloadWithExistingObject();     //  ok      ok      ok      ok      ok
await TestDownloadWithNonexistingObject();  //  ok      ok      ok      ok      ok
await TestDownloadFromInvalidEndpoint();    //  ok      ok      NOK     NOK     different exception

Previous versions did throw a ConnectionException, with your latest code a HttpRequestException is thrown.
In our environment it would probably be ok to receive a different exception in these cases, but generally I would consider this a breaking change.

@ebozduman
Copy link
Collaborator Author

ebozduman commented Jul 29, 2024

@rhegner,
Thank you very much for testing the fix.
I'll look into the regressed exceptions.
I am also running our functional tests against 3 scenarios:

  • Nonexisting endpoint
  • Invalid access key
  • Invalid secret key
    I'll work on all the anomalies and regressions I see in these tests.

@ebozduman ebozduman force-pushed the swallowed-exceptions-when-server-down branch from 136a563 to 6de3c2a Compare August 8, 2024 04:37
@harshavardhana
Copy link
Member

@rhegner, Thank you very much for testing the fix. I'll look into the regressed exceptions. I am also running our functional tests against 3 scenarios:

  • Nonexisting endpoint
  • Invalid access key
  • Invalid secret key
    I'll work on all the anomalies and regressions I see in these tests.

@ebozduman is this done?

@ebozduman
Copy link
Collaborator Author

ebozduman commented Oct 2, 2024

@harshavardhana

It is incomplete!

Replaced the existing hack fix and cleaned up all the extra code.
Also made changes according to Ramon's suggestions.
But since this change touches everybody, testing took quite sometime.
There is another tune up that needs to be done for a test, but before finishing and testing the required change, I switched to the AI storage testing. So, it is still incomplete.

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.

BucketExistsAsync returns true even if it does not exist
5 participants