我有一个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来确保在使用完本机资源之前不会运行终结器。
我是否会因为某种原因(除了应用程序关闭(而不报告异常?
据我所知,不是因为任何收集问题。但可能还有其他考虑因素,比如无法弥补的例外情况。