Sunday, April 15, 2012

Switch Stream Pattern in Reactive Extensions

This post discusses and shows a usage pattern for Switch operator in Reactive Extensions. There are more than a handful of Reactive operators that I havent yet found the use for. I have however used Switch operator effectively. Here is my scenario that exploits switch.

Before we begin, Its important to understand that subscribing in Rx is a two step process:

  1. Create a Stream
  2. Subscribe to the stream.
Its implicit in above steps that stream must be created before you can subscribe to it. Switch allows a scenario where you want the subscription to go ahead even though you dont really have the real stream yet. That means, step 2 above can happen without step 1. That sounds counter intuitive but that's what switch allows us to do. Its obvious that you need a stream to subscribe to, you can create an empty stream to kind of fulfill the role of an actual stream until we get the actual stream. In this post, I am using the word Subscriber or Client interchangeably, both mean the same: subscriber to an Observable.

Set up:
- Client wants a stream of data

Design Constraint:
-  You want to give it out conditionally. It can be due to:
  • You are not ready due to lack of availability of business logic. In other words, business logic that governs readiness of the stream will come after client has asked for the stream. The fact that subscription to the stream happens after business logic is available is inconsequential.
  • Business logic dictating the availability of stream can change at any time, even after the client has subscribed. We must account for the case where business logic reverts the condition such that stream is no longer available to the subscriber(client).
-  Client/Subscriber shouldnt have to worry about the business logic dictating the availability of the actual stream. It should stay with the source(observable).

In other words, whenever you, as an owner of a stream is not sure about giving the stream to potential clients who want to subscribe to it, use a Switch Stream. A Switch Stream allows you to change your mind later without letting the client interfere in any way or know about it.

For example, lets say you have the following stream of longs that client is interested in:

At the time client makes a request for the stream for potential subsequent subscription, you are not certain if you want to give this out or you may not have the stream. You however don't want to stop the client from having some stream and subscribing to it. To compensate for lack of our readiness, lets create a dummy empty stream(of the same type as the actual stream), which we would like clients to have until we decide if we want to hand out the real stream.

What we want to do is the following:

We want to do this in such a way that no action from source or subscriber is required. To simulate the bool condition, we now have a stream of bools which will drive the switch between two streams(real and empty ones):

Now that we have the following three streams,
  1. Real stream (of type long in this case)
  2. Empty stream (always of the same type as the real stream)
  3. Driver stream (always of type bool)
we can create the switch stream that can be handed out to potential subscriber. Client will get and subscribe to switchStream even though client wanted actualLongStream. Its important to understand that our intention here is whenever the value of boolStream is true, we want to give out actualLongStream; otherwise we want to give out emptyLongStream. Client is however oblivious to all this:

At this point our stream is constructed and is ready for subscription. Following will not do anything as the stream hasn't become hot yet:

However if at this stage, if we do the following and drive our bool stream, we will see that the client has automatically subscribed to the actual stream and is getting data from it:

Similarly, the client can be switched back to empty stream by doing the following:

Switch does subscribe/unsubscribe behind the scenes. To verify this, I went back to subscription snooping discussed here. I altered my streams to log sub/dispose:

Ticking the bool stream to false like this:

shows that empty long stream was subscribed to(due to boolStream.OnNext(false)):


Now if we tick the bool stream to true:

we can see that previously subscribed empty stream has been unsubscribed and actual long stream has been subscribed. Since actual stream is hot, you see the data as well. All this sub/unsub switching is done by Switch behind the scenes:


Summary:

- Consider using Switch operator when you want to conditionally give out the observable.

Using switch operator: 
- Create the desired stream as you normally would.
- Create an empty stream of the same type as the desired stream.
- Create a bool stream which will tick based on some condition known to the source.
- Create a switch stream which is driven by the bool stream

No comments:

Post a Comment