0

The application has the following definition

IDisposable IObservable<X>.Subscribe<X>(Action<X> onNext)

It was passed an async function:

async Task Process(X notification, CancellationToken ct) {...}

source.Subscribe(async x => await Process(x, CancellationToken.None)); // Warning

However, ReSharper warns "avoid using 'async' lambda when delegate type returns 'void'", because the exception raised in Process will not be caught with Catch.

The following code doesn't have any warning. However, I heard using Wait() is usually a bad code smell?

source.Subscribe(x => Process(x, CancellationToken.None).Wait());
ca9163d9
  • 27,283
  • 64
  • 210
  • 413
  • If the event occurs, and then an error is thrown, how are you going to log / notify the user? What about if there are multiple events fired before the process finishes? Do you want to block a thread? Do you need a work queue? You haven't provided enough context to really answer this question. – Jeremy Lakeman Apr 05 '23 at 06:32
  • 1
    Related: [How to call back async function from Rx Subscribe?](https://stackoverflow.com/questions/23006852/how-to-call-back-async-function-from-rx-subscribe), and also maybe this: [Concurrent subscriber execution in System.Reactive](https://stackoverflow.com/questions/69070794/concurrent-subscriber-execution-in-system-reactive). – Theodor Zoulias Apr 05 '23 at 07:12

1 Answers1

0

When you call an async function in the Subscribe Action then you create an async void method. It is good to always avoid async void as Resharper correctly states , since potential exceptions are disappearing in the void.

A better way to call an async function is like this: Also note the catching of the exceptions.

source
   .Select(result =>
       Observable.FromAsync(() => observer.OnCalculationFinished(result))
          .Catch((Exception ex) =>
          {
             Log.Error(ex, "Error on VEV calculation subscription for client {Client} {Quarter}.", result.VevQuarterCalculation.ClientId, result.VevQuarterCalculation.Quarter);
             return Observable.Empty<System.Reactive.Unit>();
           }))
   .Concat()
   .Subscribe();
L01NL
  • 1,753
  • 1
  • 13
  • 17
  • *"potential exceptions are disappearing in the void"* -- Actually exceptions are crashing the process. It's a common misconception that `async void` is fire-and-forget. It's more like [fire-and-crash](https://stackoverflow.com/questions/17659603/async-void-asp-net-and-count-of-outstanding-operations/17660475#17660475), as Stephen Cleary calls it. – Theodor Zoulias Apr 05 '23 at 07:35