Whether its software, a service, or a tangible product, on-time delivery is a key component to any product’s success.
Synchronoss, being an innovator and global leader in messaging, cloud, and digital platforms, has a primary goal of ensuring its customers deliver intended messages to their audience on time and accurately. Even when the message is time-sensitive and intended to be delivered during high traffic periods, the system has to scale, improve every user’s experience and be responsive. Within a system, there may be several threads going through multiple hops as part of the flow and working towards one goal, so handling threads and being responsive is quite a challenge, this is where we have found that Reactive programming assists and helps the system to scale and be responsive.
What is Reactive Programming
Reactive programming (Rx) is a programming paradigm oriented around data flows and the propagation of change. This means that it should be possible to express static or dynamic data flows with ease in the programming languages used and that the underlying execution model will automatically propagate changes through the data flow.
Rx => Observable + Observer + Scheduler
Multiple languages have implemented Reactive Programming, libraries such as RxJava, RxJS, and RxNet are available to download and use. Let’s discuss how RxJava works specifically.
RxJava
RxJava is a Java VM implementation of Reactive Extensions: a library for composing asynchronous and event-based programs by using observable sequences. It extends the observer pattern to support sequences of data/events and adds operators that allow you to compose sequences together declaratively while abstracting away concerns about things like low-level threading, synchronization, thread-safety, and concurrent data structures.
The Problem
One problem that RxJava helps to solve is when there are several concurrent threads that contain data that can solve the same problem but it is not efficient to process all of them, and instead it would be better to process one from the group. By processing one from a group, duplicate threads are filtered out which saves resources and improves the system performance.
The Use Case
One use case is document processing requests (such as upload, download, delete, etc.) from a batch job or external clients that need the ‘cached expensive calculation’ to access the storage which is shared by more than one system. In this case, there will be several concurrent requests from the same group/client, maybe each one performing a different operation.
The ‘cached calculation’ to access the storage is time-based, so a naive approach is to let every request to compute a new one and then access the storage system, but this can be very inefficient and overload the system.
Alternatively, we can let one request per group/client store the “computed calculation” in a caching system and let other threads belonging to the same group use it, but below are some of the problems one can encounter when doing it in this manner:
- What happens when the ‘cached calculation’ expires, or it does not exist in the caching system?
- Which thread is responsible to get a new calculation and update the caching system?
- How do you avoid multiple threads updating the ‘calculation’ in the caching system?
The Solution
This is where RxJava library helps. Since the computed value is time-based, it is deleted from the caching system soon after it expires.
One solution is to have a background thread whose job is to check the expiry of the time-based computed value ahead and update with a new one, but what happens if the background thread is not performing its job? This can happen for a variety of reasons. The business cannot afford to lose a request but must solve the problem in a simpler way.
As a result, we have found that RxJava library can be used to improve efficiency by:
- Handling several concurrent threads
- Collecting till a configured time
- Grouping by a client
- Filtering all except one per group
- Updating the computed value in the caching system
This way there is no dedicated background thread that updates the token which can be a single point of failure. Also, only one thread updates the computed value per group in the caching system which is more efficient than letting all threads update the caching system.
As a result, Rx libraries are helping Synchronoss to solve complex problems of asynchronous and multi-threading, ensuring our Advanced Messaging and Email Suite customer’s messages are delivered correctly and in a timely manner, while also helping to improve user experiences in the cloud products we offer our customers.