c# MediatR 的 Publish 并发策略(ParallelNoWait, SyncContinueOnException)

来源:这里教程网 时间:2026-02-21 17:36:37 作者:

MediatR 的
Publish
默认是同步顺序执行,不是并发

很多人看到

IPublisher.Publish
返回
Task
就默认它天然支持并发,其实不然。MediatR 的默认行为是:所有
IAsyncNotificationHandler<t></t>
按注册顺序**逐个 await**,一个 handler 抛异常会中断后续 handler 执行(除非显式配置异常处理策略)。这和你手动写
await handler1.Handle(...); await handler2.Handle(...);
效果一致。

ParallelNoWait
策略:真正并发但完全放弃等待与错误传播

这是 MediatR 8+ 引入的并发策略,通过

ServiceCollection
配置启用:

services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
    cfg.NotificationPublisher = new ParallelNoWaitPublisher(); // 关键
});

它会把所有 handler 包装进

Task.Run
并发启动,然后立即返回已完成的
Task.CompletedTask
—— 也就是说:

Publish
调用后几乎立刻返回,不等任何 handler 完成
handler 内部抛出的异常会被吞掉(仅记录到
ILogger
),不会向上冒泡
无法感知 handler 是否成功、耗时多久、是否被取消 不适合依赖 handler 副作用(如发消息、更新缓存)后继续逻辑的场景

SyncContinueOnException
是假“并发”,本质是同步兜底

这个策略名字有误导性:它**不并发**,也不并行。它的作用只是让某个 handler 抛异常时,不影响其他 handler 继续执行 —— 仍按注册顺序同步调用,只是把每个

Handle
包在
try/catch
里:

services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
    cfg.NotificationPublisher = new SyncContinueOnExceptionPublisher();
});

典型适用场景:

多个日志/埋点 handler,一个失败不该阻塞另一个 监控类通知(如发送指标),允许部分失败 你明确不需要 await 结果,但又希望保留调用顺序和可调试性

注意:它仍会等待全部 handler 同步执行完才返回

Task
,只是异常不中断流程。

自己实现可控并发:用
Task.WhenAll
+ 显式错误处理

如果既要并发,又要捕获结果或控制失败策略,MediatR 不提供开箱即用方案,得自己封装。常见做法是在业务层手动聚合 handler 调用:

var tasks = handlers.Select(h => h.Handle(notification, cancellationToken));
var results = await Task.WhenAll(tasks); // 等全部完成,任一失败则整体失败
// 或带错误隔离:
var results = await Task.WhenAll(
    handlers.Select(h => 
        Task.Run(() => h.Handle(notification, cancellationToken))
                .ContinueWith(t => t.Exception?.InnerException, TaskContinuationOptions.OnlyOnFaulted)
                .ContinueWith(t => t.Result ?? null)
    )
);

关键点:

必须从 DI 容器解析
IEnumerable<iasyncnotificationhandler>></iasyncnotificationhandler>
,不能靠 MediatR 自动分发
Task.WhenAll
失败时抛第一个异常;若要忽略部分失败,需用
ContinueWith
await task.OrNothing()
类辅助方法
并发数不受控时可能压垮下游(如 DB 连接池),建议配合
SemaphoreSlim
限流

MediatR 的 Publish 并发能力很轻量,真正需要可靠异步协作时,往往该考虑事件总线(如 MassTransit)或后台任务队列(如 Hangfire)了。

相关推荐