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

Exceptions within TryAsync<T>.IfFail handler re-call the same handler #1079

Open
geppettodivacin opened this issue Jun 30, 2022 · 3 comments

Comments

@geppettodivacin
Copy link

We've got several places where we would like to handle some errors, but if we can't handle the error, re-throw. This allows our the stock GRPC framework to catch that exception and send the client the correct error code, for example.

We'd like to use IfFail to do this processing, as shown below. However, whenever we rethrow, it gets handled twice. For example, the following code ends in two lines saying "We've never seen this error before!"

using static LanguageExt.Prelude;

const string unknownErrorMessage = "Catch me!";

var failure = TryAsyncFail<int>(new Exception(unknownErrorMessage));

var hopefullyNotFailure = await failure.IfFail(ex =>
    {
        if (ex.Message != unknownErrorMessage)
            return 42;

        Console.WriteLine("We've never seen this error before!");
        throw ex;
    }
);

Console.WriteLine(hopefullyNotFailure);

This is not the behavior that happens when we use Match:

var hopefullyNotFailure = await failure.Match(
    x => x,
    ex =>
    {
        if (ex.Message != unknownErrorMessage)
            return 42;

        Console.WriteLine("We've never seen this error before!");
        throw ex;
    }
);

We've resorted to using Match for the time being, but it would be more pleasant to be able to use IfFail for this, and it doesn't seem like intentional behavior. If the handler failed to handle the original error, how would we expect it to handle its own error?

@geppettodivacin
Copy link
Author

Of course, the issue is that the Fail() call is within the try and in the catch. Do we want to handle the catch with the Fail() method? Or should that be exclusively for faulted tries?

try
{
var res = await self.Try().ConfigureAwait(false);
if (res.IsFaulted)
return Fail(res.Exception);
else
return res.Value;
}
catch (Exception e)
{
TryConfig.ErrorLogger(e);
return Fail(e);
}

@louthy
Copy link
Owner

louthy commented Jun 30, 2022

I'm midway through a massive refactor at the moment, so I won't get to this any time soon. My suggestion would be that if you have a decent workaround, wrap it up in an extension method and use that; then it can all be changed later (as well as being a bit more convenient than writing out the same match expression many times).

@louthy
Copy link
Owner

louthy commented Jun 30, 2022

By the way, if you want better error handling in general, check out Aff<A> it is a better TryAsync with many more options for error handling.

You don't need to use the runtime version (Aff<RT, A>) to get the benefits. There's a load of examples in the EffectsExamples sample project.

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

No branches or pull requests

2 participants