具有全局异常处理程序的持久功能

问题描述 投票:0回答:1

我们拥有具有多个协调器和活动的持久功能。我们希望使用中间件作为全局异常处理程序,而不是在每个协调器/活动中处理它。我们可以在中间件中捕获错误,但在耐用功能监视器中实例为绿色。我们希望将其变为红色并将错误文本发送到监视器。有什么办法可以达到这个目的吗?

编辑:添加代码

internal sealed class ErrorHandlerMiddleware(ILogger<ErrorHandlerMiddleware> logger) : IFunctionsWorkerMiddleware {

    private readonly ILogger<ErrorHandlerMiddleware> _logger = logger ?? throw new ArgumentNullException(nameof(logger));

    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
        try
        {
            await next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, ex.Message);
            // How to call DurableOrchestrationContextBase.SetCustomStatus from here?
        }
    }
}
c# azure-functions middleware azure-durable-functions asp.net-core-middleware
1个回答
0
投票

我使用下面的代码使用中间件作为全局异常处理程序来处理异常。

GlobalExceptionHandlerMiddleware.cs:

public class GlobalExceptionHandlerMiddleware : IFunctionsWorkerMiddleware
{
    private readonly ILogger _logger;

    public GlobalExceptionHandlerMiddleware(ILogger<GlobalExceptionHandlerMiddleware> logger)
    {
        _logger = logger;
    }

    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
        try
        {
         // Executes the orchestration function
            await next(context); 
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An unhandled exception occurred.");
         // you can re-throw the exception to handle it elsewhere(or)mark it as failed.
            throw;  
        }
    }
}

程序.cs:

var builder = FunctionsApplication.CreateBuilder(args);

builder.ConfigureFunctionsWebApplication();

// Register exception handler middleware.
builder.UseMiddleware<GlobalExceptionHandlerMiddleware>(); 
 
builder.Build().Run();

函数.cs:

 public static class Function1
 {
     [Function(nameof(Function1))]
     public static async Task<List<string>> RunOrchestrator(
                [OrchestrationTrigger] TaskOrchestrationContext context)
     {
         var logger = context.CreateReplaySafeLogger(nameof(Function1));
         var outputs = new List<string>();

         try
         {
             outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "Tokyo"));
             context.SetCustomStatus("Tokyo");
             throw new Exception("Something went wrong in the orchestration.");

             outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "Seattle"));
             context.SetCustomStatus("Seattle");
             outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "London"));
             context.SetCustomStatus("London");

             return outputs;
         }
         catch (Exception ex)
         {
             logger.LogError($"Orchestrator failed: {ex.Message}");
             context.SetCustomStatus($"Error: {ex.Message}");
             // Rethrow the orchestration to mark it as failed
             throw new Exception("Orchestrator execution failed.", ex);
         }
     }

     [Function(nameof(SayHello))]
     public static string SayHello([ActivityTrigger] string name, FunctionContext executionContext)
     {
         var logger = executionContext.GetLogger("SayHello");
         logger.LogInformation("Saying hello to {name}.", name);
         return $"Hello {name}!";
     }

     [Function("Function1_HttpStart")]
     public static async Task<HttpResponseData> HttpStart(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req,
        [DurableClient] DurableTaskClient client,
        FunctionContext executionContext)
     {
         var logger = executionContext.GetLogger("Function1_HttpStart");
         string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(nameof(Function1));

         logger.LogInformation("Started orchestration with ID = '{instanceId}'.", instanceId);
         return await client.CreateCheckStatusResponseAsync(req, instanceId);
     }

输出:

Functions:

        Function1_HttpStart: [GET,POST] http://localhost:7182/api/Function1_HttpStart

        Function1: orchestrationTrigger

        SayHello: activityTrigger

For detailed output, run func with --verbose flag.
[2024-12-02T09:52:41.939Z] Host lock lease acquired by instance ID '000000000000000000000000F72731CC'.
[2024-12-02T09:52:43.675Z] Executing 'Functions.Function1_HttpStart' (Reason='This function was programmatically called via the host APIs.', Id=e618a276-60b9-4feb-84ce-3db17390ca3c)
[2024-12-02T09:52:59.923Z] Scheduling new Function1 orchestration with instance ID '0958069fc24c4678b7486bf01fc6b995' and 0 bytes of input data.
[2024-12-02T09:53:00.275Z] Started orchestration with ID = '0958069fc24c4678b7486bf01fc6b995'.
[2024-12-02T09:53:00.398Z] Executed 'Functions.Function1_HttpStart' (Succeeded, Id=e618a276-60b9-4feb-84ce-3db17390ca3c, Duration=16761ms)
[2024-12-02T09:53:00.438Z] Executing 'Functions.Function1' (Reason='(null)', Id=34b6427d-ccfa-4c8b-8b0e-49dd33e86521)
[2024-12-02T09:53:06.458Z] Executed 'Functions.Function1' (Succeeded, Id=34b6427d-ccfa-4c8b-8b0e-49dd33e86521, Duration=6070ms)
[2024-12-02T09:53:06.551Z] Executing 'Functions.SayHello' (Reason='(null)', Id=2f65ef8f-bba4-4eca-9c9c-f5c3884c462a)
[2024-12-02T09:53:08.907Z] Saying hello to Tokyo.
[2024-12-02T09:53:08.913Z] Executed 'Functions.SayHello' (Succeeded, Id=2f65ef8f-bba4-4eca-9c9c-f5c3884c462a, Duration=2369ms)
[2024-12-02T09:53:08.985Z] Executing 'Functions.Function1' (Reason='(null)', Id=4a739a12-8f60-4b48-b24d-1699a98254b4)

[2024-12-02T09:53:10.430Z] Orchestrator failed: Something went wrong in the orchestration.
[2024-12-02T09:53:10.704Z] An unhandled exception occurred.
[2024-12-02T09:53:10.708Z] Result: An unhandled exception occurred.
Exception: System.Exception: Orchestrator execution failed.
[2024-12-02T09:53:10.712Z]  ---> System.Exception: Something went wrong in the orchestration.
[2024-12-02T09:53:10.715Z]    at FunctionApp11.Function1.RunOrchestrator(TaskOrchestrationContext context) in C:\Users\uname\Source\Repos\FunctionApp11\Function1.cs:line 25
[2024-12-02T09:53:10.719Z]    --- End of inner exception stack trace ---
[2024-12-02T09:53:10.723Z]    at FunctionApp11.Function1.RunOrchestrator(TaskOrchestrationContext context) in C:\Users\uname\Source\Repos\FunctionApp11\Function1.cs:line 42
//Removed few logs
[2024-12-02T09:53:10.939Z]    at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithLoggingAsync(IFunctionInstanceEx instance, FunctionStartedMessage message, FunctionInstanceLogEntry instanceLogEntry, ParameterHelper parameterHelper, ILogger logger, CancellationToken cancellationToken) in D:\a\_work\1\s\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 306. IsReplay: False. State: Failed. RuntimeStatus: Failed. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.13.7. SequenceNum er: 8. TaskEventId: -1

功能应用程序的应用洞察:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.