Skip to content

Reservoirs and parallelism

yanlu edited this page May 31, 2016 · 2 revisions

Due to the push event, pull data model and the general multi-threaded handling, an updatable may not see the full change history of a repository’s data. This is by design: in most cases (particularly for updating the app’s UI), only the latest, most up-to-date data should matter. However, if the clients should (at least collectively) know the full history of changes, Agera provides a subtype of Repository: Reservoir, that can be useful for these scenarios.

A Reservoir is the reactive version of a Queue. Data can be enqueued to the reservoir using its Receiver interface, causing it to notify its client updatables, which can in turn dequeue the same data using the reservoir’s Repository (Supplier, to be precise) interface. Access to the reservoir is fully synchronized, so no two clients will be able to dequeue the same instance of data (an instance here is defined as a successfully enqueued value; if the same value (the same Java object reference) is enqueued multiple times, they are different instances in the context of a reservoir). The return value type is wrapped into a Result, so if a client attempts to dequeue data when the repository is empty, it can receive Result.absent() as a notice of failure.

With this behavior, a reservoir is perfect for acting as the data source of some reaction that must process each piece of data. The reaction can be implemented using a compiled repository if appropriate, that uses the reservoir as one of its event sources, and starts its data processing flow with .attemptGetFrom(reservoir).orSkip(). The observable-updatable relationship between the reservoir and this compiled repository will sequentially consume all data submitted to the reservoir, as long as the repository is activated.

Simple parallelism can be achieved using a reservoir and multiple instances of otherwise identical compiled repositories, each of which uses the reservoir as its event source and data source in the aforementioned manner. Jobs can be submitted to the reservoir, and each repository will attempt to dequeue the jobs for processing in their separate data processing flows. Note that to achieve actual parallelism, these repositories must move the processing onto a multi-threaded Executor, or run on different worker Loopers.