是否需要显式释放Microsoft.Extensions.Logging.BeginScope返回的IDisposable?
关于Hangfire作业中Serilog BeginScope的资源释放问题
问题描述
我有一系列Hangfire作业,在作业的构造函数中添加了以下用于Serilog/Seq的代码:
public CheckoutExternalToursBookingJob( ...omiss... ILogger<CheckoutExternalToursBookingJob> logger, IEmailSender emailSender) { ...omiss... _logger = logger; _emailSender = emailSender; _logger.BeginScope(new Dictionary<string, object> { [CoreConstants.ApplicationName] = CoreConstants.HangFireApplicationName, [CoreConstants.HangFireJob] = JobName }); }
通过这段代码,我让所有_logger.*日志都包含指定的上下文信息。现在的疑问是:由于BeginScope返回IDisposable对象,我是否需要将其保存为局部变量,在作业中实现IDisposable接口并调用scope.Dispose()?
回答
必须处理这个IDisposable对象。
BeginScope创建的日志上下文依赖异步本地存储或当前执行上下文,若不主动释放,Hangfire复用线程池线程时,未清理的上下文会泄漏到后续作业中,导致日志上下文混乱,出现不属于当前作业的日志标签。正确实现方式:
- 在作业类中声明私有
IDisposable字段存储BeginScope的返回值; - 构造函数中初始化该字段;
- 让作业类实现
IDisposable接口,在Dispose方法中释放scope对象。
修改后的代码示例:
public class CheckoutExternalToursBookingJob : IDisposable { private readonly ILogger<CheckoutExternalToursBookingJob> _logger; private readonly IEmailSender _emailSender; private IDisposable _logScope; public CheckoutExternalToursBookingJob( ...omiss... ILogger<CheckoutExternalToursBookingJob> logger, IEmailSender emailSender) { ...omiss... _logger = logger; _emailSender = emailSender; _logScope = _logger.BeginScope(new Dictionary<string, object> { [CoreConstants.ApplicationName] = CoreConstants.HangFireApplicationName, [CoreConstants.HangFireJob] = JobName }); } public void Dispose() { _logScope?.Dispose(); } public async Task ExecuteAsync() { _logger.LogInformation("作业开始执行"); // 业务逻辑代码 } }- 在作业类中声明私有
额外说明:Hangfire会自动调用实现了
IDisposable接口的作业实例的Dispose方法,无需在作业执行方法内手动调用。这样能确保每个作业的日志上下文在执行完毕后被彻底清理,不会干扰其他作业的日志输出。
内容的提问来源于stack exchange,提问作者advapi
相关产品推荐
相关产品推荐

