@@ -18,49 +18,62 @@ public DefaultBackgroundPublisher(IServiceScopeFactory scopeFactory)
1818 /// <inheritdoc />
1919 public void Publish ( object notification )
2020 {
21- _ = Task . Run ( async ( ) =>
21+ ObserveTask ( Task . Run ( async ( ) =>
2222 {
2323 using var scope = _scopeFactory . CreateScope ( ) ;
2424 var mediator = scope . ServiceProvider . GetRequiredService < IPublisher > ( ) ;
2525
2626 await mediator . Publish ( notification , CancellationToken . None ) ;
27- } , CancellationToken . None ) ;
27+ } , CancellationToken . None ) ) ;
2828 }
2929
3030 /// <inheritdoc />
3131 public void Publish ( MediatorNamespace ns , object notification )
3232 {
33- _ = Task . Run ( async ( ) =>
33+ ObserveTask ( Task . Run ( async ( ) =>
3434 {
3535 using var scope = _scopeFactory . CreateScope ( ) ;
3636 var mediator = scope . ServiceProvider . GetRequiredService < IPublisher > ( ) ;
3737
3838 await mediator . Publish ( ns , notification , CancellationToken . None ) ;
39- } , CancellationToken . None ) ;
39+ } , CancellationToken . None ) ) ;
4040 }
4141
4242 /// <inheritdoc />
4343 public void Publish < TNotification > ( TNotification notification ) where TNotification : INotification
4444 {
45- _ = Task . Run ( async ( ) =>
45+ ObserveTask ( Task . Run ( async ( ) =>
4646 {
4747 using var scope = _scopeFactory . CreateScope ( ) ;
4848 var mediator = scope . ServiceProvider . GetRequiredService < IPublisher > ( ) ;
4949
5050 await mediator . Publish ( notification , CancellationToken . None ) ;
51- } , CancellationToken . None ) ;
51+ } , CancellationToken . None ) ) ;
5252 }
5353
5454 /// <inheritdoc />
5555 public void Publish < TNotification > ( MediatorNamespace ns , TNotification notification )
5656 where TNotification : INotification
5757 {
58- _ = Task . Run ( async ( ) =>
58+ ObserveTask ( Task . Run ( async ( ) =>
5959 {
6060 using var scope = _scopeFactory . CreateScope ( ) ;
6161 var mediator = scope . ServiceProvider . GetRequiredService < IPublisher > ( ) ;
6262
6363 await mediator . Publish ( ns , notification , CancellationToken . None ) ;
64- } , CancellationToken . None ) ;
64+ } , CancellationToken . None ) ) ;
65+ }
66+
67+ /// <summary>
68+ /// Observes faulted fire-and-forget tasks so they do not trigger
69+ /// <see cref="TaskScheduler.UnobservedTaskException"/> and crash the process.
70+ /// </summary>
71+ private static void ObserveTask ( Task task )
72+ {
73+ task . ContinueWith (
74+ static t => GC . KeepAlive ( t . Exception ) ,
75+ CancellationToken . None ,
76+ TaskContinuationOptions . OnlyOnFaulted | TaskContinuationOptions . ExecuteSynchronously ,
77+ TaskScheduler . Default ) ;
6578 }
6679}
0 commit comments