在瞬态生存期服务中记录fire-and-forget任务的异常



我有一个fire-and-forget任务,我需要在其中报告一些遥测,任务是否成功并不重要(这就是为什么它是fire-and-forget(,但我需要确保它不会阻塞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();

CCD_ 1和CCD_ 2被创建并注入到具有瞬态寿命的容器中。

我的问题是:

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

我是否会因为某种原因(除了应用程序关闭(而冒着不报告异常的风险?

非常感谢您的帮助。

新线程中对logger的引用会阻止MyService/Reporter被收集吗?

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

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

这个对象将被执行线程的堆栈或任务队列引用。但是logger并没有真正在任何对象的寿命方面发挥任何作用,因为它是一个静态场。

或者GC会在记录器之前决定释放服务吗。是否调用了警告?

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

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

我是否会因为某种原因(除了应用程序关闭(而不报告异常?

据我所知,不是因为任何收集问题。但可能还有其他考虑因素,比如无法弥补的例外情况。

最新更新