1

I have to ensure an Observable to complete. It is observing stream data, which isn't in my focus to modify. The stream data may not tick at all. I came across using a subject member that I can use to manually complete the observable.

private readonly Subject<bool> _mySubject = new Subject<bool>();

// relevant property that should be completed
public IObservable<myModel> StreamObservable { get; private set; }

IObservable<myModel> someDataObservable = ... ; // may not tick in scenario

// this doesn't work            
StreamObservable = someDataObservable
                .TakeUntil(_mySubject)
                .Finally(() => logger.LogInformation("completed!"));
_mySubject.OnNext(true);

// I tried Amb.. still not going into Finally(), also when someDataObservable doesn't tick
StreamObservable = Observable.Amb(_mySubject.SelectMany(value => Observable.Empty<myModel>()), someDataObservable)
                .Finally(() => logger.LogInformation("completed!"));
_mySubject.OnNext(true);

How can I complete, preferably using Subject.OnNext() ?

The subject trigger is just an idea. My preference is to stay in the observale world and transform the sequence to Observable.Empty(), e.g. when a callback like this is invoked:

private Task<bool> FinishStreamCallback()
{
    _mySubject.OnNext(true); // my first approach
    return Task.FromResult(true);
}

..targeting using OnCompleted()-subscriptions of the relevant public observable in another class.

deafjeff
  • 754
  • 7
  • 25

1 Answers1

1

Using a subject like that doesn't end the observable. It's not like the source of the observable called OnCompleted. Using TakeUntil causes the subscription of the source observable to be disposed.

It's like this code:

var source = new Subject<int>();
var subscription = source.Materialize().Subscribe(x => Console.WriteLine(x.Kind));
source.OnNext(1);
subscription.Dispose();

This only displays OnNext.

If I run this:

var source = Observable.Return(42);
var subscription = source.Materialize().Subscribe(x => Console.WriteLine(x.Kind));

Then I get:

OnNext
OnCompleted

Calling .Dispose(), explicitly or through TakeUntil, causes the source observable to stop where it is. No OnCompleted is produced.

If you want to know when an observable is unsubscribed then try this extension method:

public static IObservable<T> OnUnsubscribe<T>(this IObservable<T> source, Action unsubscribe) =>
    Observable
        .Create<T>(o =>
            new CompositeDisposable(
                source.Subscribe(o),
                Disposable.Create(unsubscribe)));
                

Try using it like this:

var source = new Subject<int>();
var trigger = new Subject<Unit>();
var subscription =
    source
        .Materialize()
        .OnUnsubscribe(() => Console.WriteLine("Unsubscribed!"))
        .TakeUntil(trigger)
        .Subscribe(x => Console.WriteLine(x.Kind));
        
source.OnNext(1);
trigger.OnNext(Unit.Default);

That gives me:

OnNext
Unsubscribed!
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • good explanation. But then I would have to use a property like bool unsubscribed in the OnUnsusbscribe, leaving the observable disposed. My preference is really to modify the observable to completed. PLease see my edit above.Thx. – deafjeff Jun 29 '20 at 08:26
  • @deafjeff - I'm not sure I understand what you mean by "property like bool unsubscribed in the OnUnsusbscribe, leaving the observable disposed"? – Enigmativity Jun 29 '20 at 08:30
  • the OnSubscribed() is working and gets triggered. But actually I'm in a sort of event subscription of an observable that has just ticked. Going on here, i would have to operate using new public bool property stating to other classes that something has changed. But the Observale is the property which is public to other classes, and part of a bigger pipeline. And i like that one to get transformed,(here: to OnCompleted()) – deafjeff Jun 29 '20 at 08:53
  • @deafjeff - If your observable is completely encapsulated then perhaps a `Subject` is all you need in the class - expose that as your public observable. You have complete control then. – Enigmativity Jun 29 '20 at 09:00