Skip to content

Commit 2185e39

Browse files
Exception throwing
1 parent a8ab204 commit 2185e39

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

src/Features/Core/Portable/Extensions/ExtensionMessageHandlerService.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System.IO;
1212
using System.Linq;
1313
using System.Reflection;
14+
using System.Runtime.CompilerServices;
1415
using System.Text.Json;
1516
using System.Threading;
1617
using System.Threading.Tasks;
@@ -41,6 +42,8 @@ internal sealed class ExtensionMessageHandlerService(
4142
IExtensionMessageHandlerFactory customMessageHandlerFactory)
4243
: IExtensionMessageHandlerService
4344
{
45+
private static readonly ConditionalWeakTable<IExtensionMessageHandlerWrapper, IExtensionMessageHandlerWrapper> s_disabledExtensionHandlers = new();
46+
4447
private readonly SolutionServices _solutionServices = solutionServices;
4548
private readonly IExtensionMessageHandlerFactory _customMessageHandlerFactory = customMessageHandlerFactory;
4649

@@ -226,19 +229,28 @@ private async ValueTask<string> HandleExtensionMessageInCurrentProcessAsync<TArg
226229
throw new InvalidOperationException($"Multiple handlers found for message {messageName}.");
227230

228231
var handler = handlers[0];
232+
if (s_disabledExtensionHandlers.TryGetValue(handler, out _))
233+
throw new InvalidOperationException($"Handler was disabled due to previous exception.");
229234

230235
try
231236
{
232237
var message = JsonSerializer.Deserialize(jsonMessage, handler.MessageType);
233238
var result = await handler.ExecuteAsync(message, executeArgument, cancellationToken).ConfigureAwait(false);
234239
return JsonSerializer.Serialize(result, handler.ResponseType);
235240
}
236-
catch
241+
catch (Exception ex) when (DisableHandlerAndPropagate(ex))
237242
{
238-
// Any exception thrown in this method is left to bubble up to the extension.
239-
// But we unregister all handlers from that assembly to minimize the impact of a bad extension.
240-
await UnregisterExtensionAsync(assemblyFilePath: handler.ExtensionIdentifier, cancellationToken).ConfigureAwait(false);
241-
throw;
243+
throw ExceptionUtilities.Unreachable();
244+
}
245+
246+
bool DisableHandlerAndPropagate(Exception ex)
247+
{
248+
FatalError.ReportNonFatalError(ex, ErrorSeverity.Critical);
249+
250+
// Any exception thrown in this method is left to bubble up to the extension. But we unregister this handler
251+
// from that assembly to minimize the impact.
252+
s_disabledExtensionHandlers.TryAdd(handler, handler);
253+
return false;
242254
}
243255
}
244256

src/Features/Core/Portable/Extensions/IExtensionMessageHandlerWrapper.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@
88

99
namespace Microsoft.CodeAnalysis.Extensions;
1010

11+
internal interface IExtensionMessageHandlerWrapper
12+
{
13+
}
14+
1115
/// <summary>
1216
/// Wrapper for an <c>IExtensionWorkspaceMessageHandler</c> or <c>IExtensionDocumentMessageHandler</c>
1317
/// as returned by <see cref="IExtensionMessageHandlerFactory"/>.
1418
/// </summary>
1519
/// <typeparam name="TArgument">The type of object received as parameter by the extension message
1620
/// handler.</typeparam>
17-
internal interface IExtensionMessageHandlerWrapper<TArgument>
21+
internal interface IExtensionMessageHandlerWrapper<TArgument> : IExtensionMessageHandlerWrapper
1822
{
1923
/// <summary>
2024
/// The type of object received as parameter by the extension message handler.

0 commit comments

Comments
 (0)