You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Serilog结合MassTransit Sink:IBus服务解析引发无限循环求助

解决Serilog Sink与MassTransit IBus的循环依赖问题

问题背景

搭建通过MassTransit发布日志消息的Serilog Sink时,启动阶段出现无限循环。核心原因是循环依赖:创建Serilog日志记录器需要依赖IBus实例的Sink,而MassTransit的IBus初始化过程又需要ILogger,导致双方初始化时互相触发,陷入循环调用。

原启动代码(Program.cs):

// 配置MassTransit,IBus已注册到DI容器
builder.Host.SetupMassTransit(); 

builder.Host.UseSerilog((ctx, services, lc) =>
{
    lc.WriteTo.Sink(new MassTransitSink(services.GetService<IBus>())); // 断点显示此处被反复调用
});

原MassTransitSink代码:

public class MassTransitSink : ILogEventSink
{
    private readonly IBus bus;

    public MassTransitSink(IBus bus)
    {
        this.bus = bus;
    }

    public async void Emit(LogEvent logEvent)
    {
        await bus.Publish<MyLog>(new MyLog("Hello World"));
    }
}

public class MyLog
{
    public MyLog(string message)
    {
        Message = message;
    }

    public string Message { get; set; } 
}

解决方案

通过延迟获取IBus实例打破循环依赖,避免在Serilog初始化阶段直接解析IBus,改为在首次处理日志事件时再初始化IBus。同时修复async void的潜在问题(未捕获异常会导致程序崩溃)。

1. 修改MassTransitSink实现

注入IServiceProvider并使用Lazy<IBus>延迟加载IBus实例,同时将Emit方法改为async Task:

public class MassTransitSink : ILogEventSink
{
    private readonly Lazy<IBus> _lazyBus;

    // 注入DI容器的服务提供器,而非直接注入IBus
    public MassTransitSink(IServiceProvider serviceProvider)
    {
        _lazyBus = new Lazy<IBus>(() => serviceProvider.GetRequiredService<IBus>());
    }

    // 替换async void为async Task,避免未捕获异常
    public async Task Emit(LogEvent logEvent)
    {
        try
        {
            // 首次调用时才会初始化IBus,此时MassTransit已完成启动
            await _lazyBus.Value.Publish<MyLog>(new MyLog(logEvent.RenderMessage()));
        }
        catch (Exception ex)
        {
            // 日志发布失败时降级处理,避免影响主程序
            Console.WriteLine($"日志发布失败: {ex.Message}");
        }
    }
}

2. 调整Serilog配置

修改Serilog初始化代码,传入IServiceProvider而非直接获取IBus:

builder.Host.SetupMassTransit(); 

builder.Host.UseSerilog((ctx, services, lc) =>
{
    lc.WriteTo.Sink(new MassTransitSink(services));
});

原理说明

  • Lazy<IBus>确保IBus实例仅在首次处理日志事件时才从DI容器中解析,此时MassTransit已完成初始化,ILogger也已就绪,彻底打破循环依赖链。
  • 替换async void为async Task,让Serilog能正确处理异步操作中的异常,避免未捕获异常导致程序崩溃。

内容的提问来源于stack exchange,提问作者Moniker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 13:20:37