首页 > 解决方案 > 在瞬态生命周期服务中记录火灾并忘记任务的异常

问题描述

我有一个火而忘记的任务,我需要报告一些遥测,任务是否成功都没有关系(这就是为什么它是火而忘记),但我需要确保它不会阻塞 api 调用.

当遥测任务中出现异常时,我会记录异常。

我的代码是这样的:

public class MyService : IMyService
{
    private readonly IReporter reporter;
    private static readonly Logger logger = LogManager.GetCurrentClassLogger();

    public MyService (IReporter reporter){

    }
    //..
    public Task<Result> processorRequest()
    {
        // ...
        _ = Task.Run(() =>
        {
            reportTelemetry();
        });

        //...
    }

    private void reportTelemetry()
    {
        try
        {
            reporter.Report();
        }
        catch (Exception ex)
        {
            logger.Warn($"An exception was raised while reporting: {ex.Message}");
        }
    }
}

记录器在顶部创建,如下所示:

private static readonly Logger logger = LogManager.GetCurrentClassLogger();

MyService并且它们Reporter被创建并注入到具有瞬态生命周期的容器中。

我的问题是:

新线程中对记录器的引用会阻止MyService/Reporter被收集吗?logger.Warn或者 GC 会在调用之前就决定释放服务吗?

由于某种原因(除了应用程序关闭),我是否有风险不报告异常?

任何帮助深表感谢。

标签: c#multithreadingloggingtaskunity-container

解决方案


新线程中对记录器的引用会阻止收集 MyService/Reporter 吗?

不,但是对 的引用this将确保服务保持活动状态,直到委托开始运行。lambda 本质上将被重写为

public class MyHiddenDelegate{
    private MyService service;
    public MyHiddenDelegate(MyService service) => this.service = service;
    public void Execute() => service.reportTelemetry();
}

并且这个对象将被执行线程的堆栈或任务队列引用。但是logger由于它是一个静态字段,因此对于任何对象的生命周期并没有真正发挥任何作用。

或者 GC 会在调用 logger.Warn 之前决定释放服务吗?

GC 必须保持对象处于活动状态,直到最后一次使用任何引用。因此,该服务可能有资格在调用 之前进行收集logger.Warn,因为它不需要this引用来访问记录器。但这通常很好,因为 GC 将确保在最后一次使用之前没有收集任何内容。

如果您拥有本机资源,则可能是一个例外。然后,您可能需要使用GC.KeepAlive来确保在完成本机资源之前不会运行终结器。

由于某种原因(除了应用程序关闭),我是否有风险不报告异常?

据我所知,不是因为任何收藏问题。但可能还有其他考虑因素,例如无法捕获的异常。


推荐阅读