Skip to content

.Net: [Error handling] [Part7] Removing IsCriticalException extension method - #2516

Closed
SergeyMenshykh wants to merge 2 commits into
microsoft:mainfrom
SergeyMenshykh:error-handling-part7
Closed

.Net: [Error handling] [Part7] Removing IsCriticalException extension method#2516
SergeyMenshykh wants to merge 2 commits into
microsoft:mainfrom
SergeyMenshykh:error-handling-part7

Conversation

@SergeyMenshykh

Copy link
Copy Markdown
Contributor

Motivation and Context

This PR is one of the follow-up PRs aimed at gradually replacing SK custom exceptions with SKException to provide a simple, consistent, and extensible exception model. You can find more details in the ADR discussing error handling.

Description

This PR removes the IsCriticalException extension method and updates all the code that used it. In a few cases, the change triggers the CA1031 - Do not catch general exception types warning, which is temporarily suppressed to keep this PR focused on removing the IsCriticalException extension method. The proper fix for these cases will be applied by one of the following PRs dedicated to the fix.

Contribution Checklist

@SergeyMenshykh
SergeyMenshykh requested a review from a team as a code owner August 21, 2023 17:37
@shawncal shawncal added .NET Issue or Pull requests regarding .NET code kernel Issues or pull requests impacting the core kernel kernel.core labels Aug 21, 2023
@SergeyMenshykh SergeyMenshykh added PR: ready for review All feedback addressed, ready for reviews and removed kernel Issues or pull requests impacting the core kernel labels Aug 21, 2023

@lemillermicrosoft lemillermicrosoft left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why are we removing IsCriticalException? The ADR only mentions it in that it will be updated to include StackOverflowException and OutOfMemoryException.

Comment thread dotnet/src/Extensions/Planning.StepwisePlanner/StepwisePlanner.cs Outdated
@shawncal shawncal added the kernel Issues or pull requests impacting the core kernel label Aug 22, 2023

@dmytrostruk dmytrostruk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As mentioned by @lemillermicrosoft , would be nice to see updates in ADR with details why IsCriticalException is removed/replaced.

@SergeyMenshykh

Copy link
Copy Markdown
Contributor Author

Why are we removing IsCriticalException? The ADR only mentions it in that it will be updated to include StackOverflowException and OutOfMemoryException.

Yes, right, it's not part of ADR. It popped up later as a comment in one of the 'Erro handling' PRs where we (@rogerbarreto , @stephentoub and me) agreed that there's no value in having it.
image
Link - https://github.com/microsoft/semantic-kernel/pull/2263/files/02abc1c868a259e081bb144f869cf09fcecd8416#diff-160896cef4bb4f4f3256d65cadf09f8d0e223b06a1b1c1184647780e8d319a37

Let's discuss this on parking lot. CC: @shawncal

@rogerbarreto rogerbarreto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

By removing the function IsCriticalException we are pratically considering any exceptions to be "critical" (should throw), I would expect the change to be either:

  1. Remove all the catch block
  2. Keep the catch just to log and throw after

return completionResponse.ConvertAll(c => new TextCompletionStreamingResult(c));
}
catch (Exception e) when (e is not AIException && !e.IsCriticalException())
catch (Exception e) when (e is not AIException)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

MSIL for catch + when is way more costly than using the below. Apply the same for the others.

Suggested change
catch (Exception e) when (e is not AIException)
catch (AIException aiex)
{
throw;
}
catch (Exception ex)

catch (Exception ex)
{
nextStep.Observation = $"Error invoking action {nextStep.Action} : {ex.Message}";
this._logger?.LogWarning(ex, "Error invoking action {Action}", nextStep.Action);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The exception is being swallowed and no log data is being stored about it.

LogWarning should be LogError or at least include the exception details.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I will tag @lemillermicrosoft for input here.

The exception is being swallowed

As far as I know, this is expected behavior for StepwisePlanner, when it receives an exception, it will put details in Observation field and proceed to the next step.

LogWarning should be LogError

In case this is correct behavior, we shouldn't log it as error, because it doesn't break the application flow, instead it's just transient error. Previously we used Debug level here, and I updated it to Warning, and it's still not clear whether it was right choice.

or at least include the exception details.

As far as I can see, we include ex instance as first parameter to LogWarning method.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes thank you @dmytrostruk . I think LogDebug is probably best in this scenario (I was gonna change in another PR).

catch (Exception e)
{
this._logger?.LogError(e, "Something went wrong in system step: {0}.{1}. Error: {2}", targetFunction.SkillName, targetFunction.Name, e.Message);
return $"Something went wrong in system step: {targetFunction.SkillName}.{targetFunction.Name}. Error: {e.Message} {e.InnerException.Message}";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
return $"Something went wrong in system step: {targetFunction.SkillName}.{targetFunction.Name}. Error: {e.Message} {e.InnerException.Message}";
return $"Something went wrong in system step: {targetFunction.SkillName}.{targetFunction.Name}. Error: {e.Message} {e.InnerException?.Message}";

return await this._function(null, settings, context, cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (!e.IsCriticalException())
catch (Exception e)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

By removing the function IsCriticalException we are pratically considering any exceptions to be "critical" (should throw).

Two options:

  1. Remove all the catch block
  2. Keep the catch just to log and throw after

}
}
catch (Exception e) when (!e.IsCriticalException())
catch (Exception e)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

By removing the function IsCriticalException we are pratically considering any exceptions to be "critical" (should throw).

Two options:

  1. Remove all the catch block
  2. Keep the catch just to log and throw after

catch (Exception e) when (!e.IsCriticalException())
catch (Exception e)
{
this.Logger.LogError(e, "Something went wrong in pipeline step {0}: {1}.{2}. Error: {3}",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
this.Logger.LogError(e, "Something went wrong in pipeline step {0}: {1}.{2}. Error: {3}",
this._logger.LogError(e, "Something went wrong in pipeline step {0}: {1}.{2}. Error: {3}",

return parser(value, context.Culture);
}
catch (Exception e) when (!e.IsCriticalException())
catch (Exception e)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

By removing the function IsCriticalException we are pratically considering any exceptions to be "critical" (should throw).

Two options:

  1. Remove all the catch block
  2. Keep the catch just to log and throw after

return converter.ConvertFromString(context: null, cultureInfo, input);
}
catch (Exception e) when (!e.IsCriticalException() && cultureInfo != CultureInfo.InvariantCulture)
catch (Exception) when (cultureInfo != CultureInfo.InvariantCulture)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

By removing the function IsCriticalException we are pratically considering any exceptions to be "critical" (should throw).

Two options:

  1. Remove all the catch block
  2. Keep the catch just to log and throw after

@rogerbarreto rogerbarreto added the PR: breaking change Pull requests that introduce breaking changes label Aug 22, 2023
@SergeyMenshykh

Copy link
Copy Markdown
Contributor Author

Closing the PR due to a lack of consensus regarding the removal of the method. Additionally, it seems that the method can be useful in distinguishing between actionable and non-actionable exceptions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kernel Issues or pull requests impacting the core kernel .NET Issue or Pull requests regarding .NET code PR: breaking change Pull requests that introduce breaking changes PR: ready for review All feedback addressed, ready for reviews

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants