Reactive Programming in Java
Reactive Programming in Java
Reactive
Programming
in Java eMag Issue 48 - Feb 2017
Testing RxJava
You are ready to explore reactive opportunities in
your code but you are wondering how to test out the
reactive idiom in your codebase. In this article Java
Champion Andres Almiray provides techniques and
tools for testing RxJava.
Reactor by Example
Reactor, like RxJava 2, is a fourth generation
reactive library launched by Spring custodian
Pivotal. It builds on the Reactive Streams
specification, Java 8, and the ReactiveX vocabulary.
In this article, we draw a parallel between Reactor
and RxJava, and showcase the common elements as
well as the differences.
Refactoring to Reactive:
Anatomy of a JDBC migration
Reactive programming offers built-in solutions for
Building Reactive some of the most difficult challenges in program-
ming, including concurrency management and flow
Applications with Akka control. So you might ask - how do I get there; can I
Actors and Java 8 introduce it in phases? In this article we transform a
Akka and Java 8 make it possible to create distrib- legacy application to a reactive model using RxJava.
uted microservice-based systems that just a few
years ago were the stuff of dreams. Actor based
systems enable developers to create quickly evolv-
ing microservice architectures that can elastically
scale systems to support huge volumes of data.
FOLLOW US CONTACT US
GENERAL FEEDBACK feedback@infoq.com
ADVERTISING sales@infoq.com
EDITORIAL editors@infoq.com
A LETTER FROM
THE EDITOR
As resource consumption requirements increase and dy- Testing RxJava - Andres Almiray
namic content generation takes on new dimensions in We’re ready to explore reactive opportunities in our code
CPU utilization and data sizes, industry has responded but wondering how to test the reactive idiom in our
with non-blocking concurrency in the form of reactive codebase. In this piece, Java Champion Andres Almiray
programming. provides techniques and tools for testing RxJava.
RxJava by Example - Victor Grazi Building Reactive Applications with Akka Actors and
We start with a gentle progression of examples designed Java 8
to help climb the learning curve. The reactive specifica- Akka and Java 8 make it possible to create distributed
tion provides tools for handling asynchronous streams microservice-based systems that just a few years ago
of data and for managing flow control, making it easier were the stuff of dreams. Actor-based systems allow
to reason about overall program design. developers to create quickly evolving microservice ar-
chitectures that can elastically scale systems to support
We start with the basics and ramp up to flow control and huge volumes of data.
backpressure.
Reactive programming provides the tools for program-
ming highly scalable systems for microservices, Android
applications, and other load and CPU-intensive applica-
tions. We hope this emag will help launch your reactive
career!
Read online on InfoQ
RxJava by Example
by Victor Grazi
Reactive programming is a algebra with its scalar quantities handling, as in “this is what is
specification for dealing with to linear algebra with its vectors, supposed to happen and here
asynchronous streams of data, matrices, and tensors, essentially are the exceptions.” In reactive,
providing tools for transforming streams of data that are treated exceptions are first-class citizens,
and combining streams and for as a unit. Unlike objects in tradi- treated every bit as such. Since
managing flow control, making it tional programming, the funda- streams are generally asynchro-
easier to reason about your over- mental unit of reactive reasoning nous, it doesn’t make sense to
all program design. is the stream of events. Events throw an exception, so any ex-
can come in the form of objects, ception is instead passed as an
But easy it is not, and there is defi- data feeds, mouse movements, event in the stream.
nitely a learning curve. It reminds or even exceptions. The word
the mathematicians among us of “exception” expresses the tradi- This article will consider the fun-
the leap from learning standard tional notion of an exceptional damentals of reactive program-
ming, with a pedagogical eye on Before you try out some exam- we’ll be using in the code sam-
internalizing the important con- ples, include the RxJava depen- ples later in this article.
cepts. dencies in your codebase. You
can load it from Maven using the Observable.just produces an
The first thing to keep in mind dependency: (Code 1) Observable that emits a single
is that in reactive everything is generic instance, followed by a
a stream. The Observable is the The Observable class has doz- complete. For example: (Code 2)
fundamental unit that wraps a ens of static factory methods and
stream. Streams can contain zero operators, each in a wide variety That creates a new Observable
or more events, may or may not of flavors for generating new that emits a single event before
complete, and may or may not Observables, or for attaching completing, the string “Howdy!”
issue an error. Once a stream them to processes of interest.
completes or issues an error, it is Observables are immutable, so We can assign that Observ-
essentially done, although there operators always produce a new able to an Observable variable.
are tools for retrying or substi- Observable. To understand our (Code 3)
tuting different streams when an code examples, let’s review the
exception occurs. basic Observable operators that
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>2.0.5</version>
</dependency>
Code 1
Observable.just(“Howdy!”)
Code 2
Observable<String> hello = Observable.just(“Howdy!”);
Code 3
Observable<String> howdy = Observable.just(“Howdy!”);
howdy.subscribe(System.out::println);
Code 4
Observable.just(“Hello”, “World”)
.subscribe(System.out::println);
Code 5
active operations. Each uses the ing String.format as our zip into an array of its component
common “marbles” reactive idi- transformation. (Code 9) characters. We will then flatMap
om to depict one or more source those to create a new Observ-
streams and the result stream Which outputs: able that consists of all of the
produced by the operator. Time characters of all of the words.
1. the
passes from left to right, and (Code 10)
2. quick
marbles on the timeline rep- 3. brown
resents events. You can click and 4. fox The output of that is:
drag the source marbles to see 5. jumped
how they affect the result. 1. t ...
6. over
2. h 30. l
7. the
3. e 31. a
A quick perusal reveals the zip 8. lazy
4. q 32. z
operation — just what the doc- 9. dog
5. u 33. y
tor ordered. Let’s look at the mar- 6. i 34. d
ble diagram to understand it bet- Looking good! 7. c 35. o
ter: (Figure 1) 8. k 36. g
Notice that the zip and zip-
zip combines the elements of With operators stop pulling from All words are present and ac-
the source stream with the el- all of the streams once any of the counted for, but there’s too much
ements of a supplied stream, streams has completed. That is data. We only want the distinct
using a pairwise “zip” transfor- why we were not intimidated by letters so we do this: (Code 11)
mation mapping that you can the Integer.MAX_VALUE upper
supply in the form of a lambda. limit. That produces:
When either of those streams 1. t
completes, the zipped stream Now, let’s say we want to list not 14. f
2. h
completes, so any remaining the words but the letters com- 15. x
3. e
events from the other stream posing those words. This is a 16. j
4. q
17. m
would be lost. zip accepts up to job for flatMap, which takes the 5. u
18. p
nine source streams and zip op- emissions (objects, collections, 6. i
19. d
erations. There is a correspond- or arrays) from an Observable 7. c
20. v
ing zipWith operator that zips and maps those elements to 8. k
21. l
a provided stream with the exist- individual Observables, then 9. b
22. a
ing stream. flattens the emissions from all of 10. r
23. z
11. o
those into a single Observable. 24. y
12. w
Coming back to our example, we 25. g
13. n
can use range and zipWith to For our example, we will use
prepend our line numbers, us- split to transform each word
Code 12
Observable.fromIterable(words)
.flatMap(word -> Observable.fromArray(word.split(“”)))
.distinct()
.sorted()
.zipWith(Observable.range(1, Integer.MAX_VALUE),
(string, count) -> String.format(“%2d. %s”, count, string))
.subscribe(System.out::println);
Code 13
As a child, I was taught that the That yields: nothing more than ways to iter-
“quick brown fox” phrase con- ate collections and produce new
tains every letter in the English 1. a 14. n collections. They are finite, stat-
alphabet but we see that there 2. b 15. o ic, and do not provide for reuse.
are only 25 letters here, not the 3. c 16. p Even when forked by the Streams
full 26. Let’s sort them to locate 4. d 17. q parallel operator, they go off
5. e 18. r
the missing one. (Code 12) and do their own fork and join,
6. f 19. s
and only return when done,
7. g 20. t
That produces: 8. h 21. u leaving the program with little
1. a 9. i 22. v control. Reactive, in contrast, in-
20. u troduces the concepts of timing,
2. b 10. j 23. w
21. v throttling, and flow control, and
3. c 11. k 24. x
22. w they can attach to “infinite” pro-
... 12. l 25. y
23. x
17. q 13. m 26. z cesses that conceivably never
24. y
18. r end. The output is not a collec-
25. z
19. t That’s a lot better! tion but is available for us to deal
with, however we require.
Looks like S is missing. Correct- So far, this all looks similar to the
ing the “quick brown fox” phrase Java Streams API introduced in Let’s take a look at some more
to the actual one (replacing Java 8. The resemblance is strict- marble diagrams to get a better
“jumped” with “jumps”) produces ly coincidental, because reactive picture.
the expected output. (Code 13) adds so much more.
The merge operator merges up to
Java Streams and lambda expres- nine source streams into the final
sions were valuable language ad- output, preserving order. There is
ditions but they are, in essence, no need to worry about race con-
Figure 5
Tick tock
Now we have the tools to combine
timed streams to produce a mean-
ingful hybrid. In the next example,
we consider a feed that pumps every
second during the week but, to save
CPU cycles, only pumps every three
seconds during the weekend. We can
Code 18
use that hybrid “metronome” to Those readers following along in filtering to schedule and merge
produce market-data ticks at the an IDE who do not want to wait them.
desired rate. until next weekend/week to see
this work may substitute the fol- We will use the Observable.
First let’s create a boolean meth- lowing implementation, which interval operation, which
od that checks the current time ticks fast for 15 seconds and then generates a tick every specified
and returns “true” for weekends slow for 15 seconds. (Code 15) number of time units (counting
and “false” for weekdays. (Code sequential Longs beginning with
14) Let’s create two Observables, 0). (Code 16)
fast and slow, and then apply
fast will emit an event every
second, slow will emit every
three seconds. (We will ignore
the Long value of the event, as
we are only interested in the tim-
ings.)
This is taken almost verbatim • BackpressureStrategy. and all subscribers would receive
from the Flowable Javadoc. The ERROR emits a Missing- the same set of historical feeds,
Flowable wraps the steps of BackpressureException if which is probably not what we
creating a listener (line 3) and the downstream can’t keep want.
registering to the service (line up.
17). Subscribers are automati- To convert this to a hot observ-
cally attached by the Flowable. • BackpressureStrategy. able so that all subscribers re-
The events generated by the ser- DROP drops the incoming ceive all notifications as they
vice are delegated to the listener onNext value if the down- occur in real time, we must call
(line 6). Line 18 tells the observer stream can’t keep up. publish and connect, as de-
to buffer all notifications until a scribed earlier. (Code 21)
subscriber consumes them. Oth- • BackpressureStrategy.
er backpressure choices are: LATEST keeps the latest on- Finally, we can subscribe and dis-
Next value and overwrites play our price ticks. (Code 22)
• BackpressureStrategy. it with newer ones until the
MISSING applies no back- downstream can consume it.
pressure. If the stream can’t
keep up, it may throw a All of this produces a cold Flow-
MissingBackpressureEx- able. As with any cold observ-
ception or IllegalState- able, it would produce no ticks
Exception. until the first observer subscribes
Testing RxJava
Andres Almiray is a Java/Groovy developer and Java Champion with more than 17 years of
experience in software design and development. He has been involved in web and desktop
application development since the early days of Java. He is a true believer in open source and
has participated in popular projects like Groovy, JMatter, Asciidoctor, and more. He is a founding
member and current project lead of the Griffon framework and is spec lead for JSR 377.
You’ve read about RxJava; you’ve played with the samples on the
internet, for example in RxJava by Example, and now you have made
a commitment to explore reactive opportunities in your own code. But
now you are wondering how to test out the new capabilities that you
might find in your codebase.
Reactive programming requires tions, built right into the core subscriptions will, by default, run
a shift in how to reason about a rxjava dependency. on the calling thread, if no partic-
particular problem, because we ular Scheduler is supplied. This
need to focus not on individual means we can setup a Subscrip-
data items but on data flowing as First Steps tion and assert its state immedi-
streams of events. These events Let’s revisit the words example ately after the subscription takes
are often produced and con- from the last article and explore place: (Code 2)
sumed from different threads, how we can test it out. Let’s be-
and so when writing tests we gin by setting up the base test Notice that we used an explicit
must keep aware of concurrency harness using JUnit as our test- List<String> to accumulate our
concerns. Fortunately RxJava2 ing framework: (Code 1) results, along with a real sub-
provides built-in support for test- scriber. Given the simple nature
ing Observables and Subscrip- Our first test will follow a naive of this test you may think that
approach, given the fact that
// then:
Custom Schedulers assertThat(results, notNullValue());
Quite often you’ll find cases in assertThat(results, hasSize(9));
assertThat(results, hasItem(“ 4. fox”));
production code where Observ-
}
ables are executed on a specific
thread, or “scheduler” in Rx par-
Code 2
// when:
observable.subscribe(observer);
// then:
observer.assertComplete();
observer.assertNoErrors();
observer.assertValueCount(9);
assertThat(observer.values(), hasItem(“ 4. fox”));
}
Code 3
@Test
public void testFailure() {
// given:
TestObserver<String> observer = new TestObserver<>();
Exception exception = new RuntimeException(“boom!”);
// when:
observable.subscribe(observer);
// then:
observer.assertError(exception);
observer.assertNotComplete();
}
Code 4
@Test
public void testUsingComputationScheduler() {
// given:
TestObserver<String> observer = new TestObserver<>();
Observable<String> observable = Observable.fromIterable(WORDS)
.zipWith(Observable.range(1, Integer.MAX_VALUE),
(string, index) -> String.format(“%2d. %s”, index, string));
// when:
observable.subscribeOn(Schedulers.computation())
.subscribe(observer);
await().timeout(2, SECONDS)
.until(observer::valueCount, equalTo(9));
// then:
observer.assertComplete();
observer.assertNoErrors();
assertThat(observer.values(), hasItem(“ 4. fox”));
}
Code 5
// when:
Iterable<String> results = observable
.subscribeOn(Schedulers.computation())
.blockingIterable();
// then:
assertThat(results, notNullValue());
assertThat(results, iterableWithSize(9));
assertThat(results, hasItem(“ 4. fox”));
}
Code 6
@Test
public void testUsingComputationScheduler() {
// given:
TestObserver<String> observer = new TestObserver<>();
Observable<String> observable = Observable.fromIterable(WORDS)
.zipWith(Observable.range(1, Integer.MAX_VALUE),
(string, index) -> String.format(“%2d. %s”, index, string));
// when:
observable.subscribeOn(Schedulers.computation())
.subscribe(observer);
observer.awaitTerminalEvent(2, SECONDS);
// then:
observer.assertComplete();
observer.assertNoErrors();
assertThat(observer.values(), hasItem(“ 4. fox”));
}
Code 7
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
Code 8
We override two other schedul- look back what we have accom- • Any Observable can be
er producing methods for good plished so far: turned into a blocking Ob-
measure, making this rule more servable, thus enabling us
generic for other testing pur- • Subscribers process data in to synchronously wait for
poses down the road. Usage of the same thread as long as events to be produced, re-
this rule in a new testcase class there’s no specific Sched- gardless of the Scheduler
is straightforward, we simply de- uler in use. This means we used by the observable.
clare a field with the new type can make assertions on a
annotated with @Rule, like so subscriber right after it sub- • RxJava exposes an extension
(Code 12) scribes to an Observable. mechanism that enables de-
velopers to override its de-
In the end we get the same be- • TestObserver can accumulate faults, and inject those right
havior as before but with less events and provide additional into the production code.
clutter. Let’s take a moment to assertions on its state.
try {
base.evaluate();
} finally {
RxJavaPlugins.reset();
}
}
};
}
}
Code 11
@Rule
public final ImmediateSchedulersRule schedulers = new ImmediateSchedulersRule();
@Test
public void testUsingImmediateSchedulersRule() {
// given:
TestObserver<String> observer = new TestObserver<>();
Observable<String> observable = Observable.fromIterable(WORDS)
.zipWith(Observable.range(1, Integer.MAX_VALUE),
(string, index) -> String.format(“%2d. %s”, index, string));
// when:
observable.subscribeOn(Schedulers.computation())
.subscribe(observer);
// then:
observer.assertComplete();
observer.assertNoErrors();
observer.assertValueCount(9);
assertThat(observer.values(), hasItem(“ 4. fox”));
}
Code 12
The “production” code changed as the scheduler has not moved We next advance time to 9 sec-
a little, as we’re now using an at this point and so no values onds from now. Mind you that
interval that is tied to the Sched- should have been produced by this means moving to exactly
uler to produce the numbering the observable nor received by 9 seconds from the scheduler’s
(line 6) instead of a range. This the subscriber. start, (and not advancing 9 sec-
has the side-effect of producing onds after already advancing
numbers starting with 0 instead Next we move time by one whole 1 before, which would result
of the original 1. Once the Ob- second (line 20), this should in the scheduler looking at 10
servable and the test scheduler cause the Observable to produce seconds after it’s start). In other
are configured we immediately the first value, and that’s exactly words, advanceTimeBy() moves
assert that the subscriber has no what the next set of assertions the scheduler’s time relative to
values (line 16), and has not com- checks (lines 23-25). its current position, whereas ad-
pleted or generated any errors vanceTimeTo()moves the sched-
(line 17). This is a sanity check uler’s time in an absolute fash-
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
RxJavaPlugins.setIoSchedulerHandler(scheduler -> testScheduler);
RxJavaPlugins.setComputationSchedulerHandler(scheduler ->
testScheduler);
RxJavaPlugins.setNewThreadSchedulerHandler(scheduler ->
testScheduler);
try {
base.evaluate();
} finally {
RxJavaPlugins.reset();
}
}
};
}
}
Code 14
@Test
public void testUsingTestSchedulersRule() {
// given:
TestObserver<String> observer = new TestObserver<>();
observable.subscribeOn(Schedulers.computation())
.subscribe(observer);
// expect
observer.assertNoValues();
observer.assertNotComplete();
// when:
testSchedulerRule.getTestScheduler().advanceTimeBy(1, SECONDS);
// then:
observer.assertNoErrors();
observer.assertValueCount(1);
observer.assertValues(“ 0. the”);
// when:
testSchedulerRule.getTestScheduler().advanceTimeTo(9, SECONDS);
observer.assertComplete();
observer.assertNoErrors();
observer.assertValueCount(9);
}
Code 15
ion. We make another round of the previous code to be rewritten ming capabilities to Java. Ver-
assertions (lines 29-31) to ensure in a more reusable form. First the sion 2.0 has been redesigned
the Observable has produced new rule: (Code 14) to better align its API with the
all data and that the subscriber Reactive Streams specification,
has consumed it all as well. One Followed by the actual test code which provides a standard for
more thing to note about the us- (in a new testcase class), to use asynchronous stream processing
age of TestScheduler is that real our test rule: (Code 15) with non-blocking back pressure,
time moves immediately, which targeting Java and JavaScript
means our test does not have to And there you have it. The usage runtimes. I highly encourage you
wait 9 seconds to complete. of a TestScheduler injected via to review the API changes made
RxJavaPlugins allow you to write since version 2.0; you can find
As you can see using this sched- the test code without altering a detailed description of these
uler is quite handy but it requires the composition of the original changes at the RxJava wiki.
you to supply the scheduler to the Observable yet it gives you the
Observable under test. This will means to modify time and make In terms of testing you’ll see
not play well with Observables assertions at specific points that the core types (Observable,
that use a specific scheduler. But during the execution of the ob- Maybe, and Single) now sport a
wait a second, we saw earlier servable itself. All the techniques handy method named test() that
how we can switch a scheduler showed in this article should give creates a TestObserver instance
without affecting production you enough options to test out for you on the spot. You may now
code using RxJavaPlugins, but RxJava enabled code. chain method calls on TestOb-
this time supplying a TestSched- server and there are some new
uler instead of an immediate assertion methods found on this
scheduler. We can even go so far The Future type, as well.
as to apply the same technique RxJava is one of the first librar-
of a custom JUnit rule, allowing ies to provide reactive program-
Reactor by Example
RxJava recap ods that create Observables This article will draw a parallel
Reactor, like RxJava 2, is a from static and dynamic sources. between Reactor and what you
fourth-generation reactive li- already learned about RxJava,
brary. Spring custodian Pivotal Observable is the push source and showcase the common ele-
launched Reactor, which builds and Observer is the simple ments as well as the differences.
on the Reactive Streams specifi- interface for consuming this
cation, Java 8, and the ReactiveX source via the act of subscribing.
vocabulary. Its design is the re- Keep in mind that the contract Reactor’s types
sult of a savant mix of designs of an Observable is to notify its Reactor’s two main types are the
and core contributors from pre- Observer of zero or more data Flux<T> and Mono<T>. A Flux is
vious versions and RxJava. items through onNext, option- the equivalent of an RxJava Ob-
ally followed by either an onEr- servable, capable of emitting
In the previous articles in this ror or onComplete terminating zero or more items, and then
eMag, “RxJava by Example” and event. optionally either completing or
“Testing RxJava”, you learned error-ing.
about the basics of reactive To test an Observable, RxJava
programming: how data is con- provides a TestSubscriber, A Mono, on the other hand, can
ceptualized as a stream, the Ob- which is a special flavor of Ob- emit once at most. It corresponds
servable class and its various server that allows you to assert to both Single and Maybe types
operators, and the factory meth- events in your stream. on the RxJava side. Thus an asyn-
chronous task that only wants Build on Rx, with It mainly deals with the concept
to signal completion can use a Reactive Streams at of reactive-pull backpressure
Mono<Void>. every stage (more on that later) and how to
As expressed in “RxJava by Ex- interoperate between several
This simple distinction between ample”, RxJava bears some su- implementing reactive sources.
two types makes things easy to perficial resemblance to the It doesn’t cover operators at all,
grasp while providing meaning- Java 8 Streams API, in terms of focusing instead exclusively on
ful semantics in a reactive API: concepts. Reactor looks a lot the stream’s lifecycle.
by just looking at the returned like RxJava, but this is of course
reactive type, you can know if a in no way a coincidence. The in- A key differentiator for Reactor is
method is more of a “fire and for- tention is to provide a Reactive its RS-first approach. Both Flux
get” or “request-response” (Mono) Streams-native library that ex- and Mono are RS Publisher im-
kind of thing or if it deals with poses an Rx-conforming oper- plementations and conform to
multiple data items as a stream ator API for asynchronous logic reactive-pull backpressure.
(Flux). composition. So while Reactor
is rooted in Reactive Streams, it In RxJava 1, only a subset of oper-
Both Flux and Mono make use seeks general API alignment with ators support backpressure, and
of this semantic by coercing the RxJava where possible. even though RxJava 1 has adapt-
relevant type when using oper- ers to RS types, its Observable
ators. For instance, calling sin- doesn’t implement these types
gle() on a Flux<T> will return Reactive libraries and directly. That is easily explained
a Mono<T>, whereas concatenat- Reactive Streams by the fact that RxJava 1 predates
ing two Monos together using adoption the RS specification; it served as
concatWith will produce a Flux. Reactive Streams (henceforth one of the foundational works
Similarly, some operators will abbreviated “RS”) is, according during the specification’s design.
make no sense on a Mono (for ex- the initiative, means “to pro-
ample take(n), which produces vide a standard for asynchro- That means that each time you
n > 1 results), whereas other op- nous stream processing with use these adapters you are left
erators will only make sense on a non-blocking backpressure.” It with a Publisher, which again
Mono (e.g. or(otherMono)). is a set of textual specifications doesn’t have any operator. In or-
along with a TCK and four sim- der to do anything useful from
One aspect of the Reactor design ple interfaces (Publisher, Sub- there, you’ll probably want to go
philosophy is to keep the API scriber, Subscription, and back to an Observable, which
lean, and this separation into two Processor) that will be integrat- means using yet another adapt-
reactive types is a good middle ed in Java 9. er. This visual clutter can be det-
ground between expressiveness rimental to readability, especially
and API surface. when an entire framework like
@Test
public void simpleCreation() {
Flux<String> fewWords = Flux.just(“Hello”, “World”);
Flux<String> manyWords = Flux.fromIterable(words);
fewWords.subscribe(System.out::println);
System.out.println();
manyWords.subscribe(System.out::println);
}
}
Code 2
Hello
World
the
quick
brown
fox
jumped
over
the
lazy
dog
Code 3
@Test
public void findingMissingLetter() {
Flux<String> manyLetters = Flux
.fromIterable(words)
.flatMap(word -> Flux.fromArray(word.split(“”)))
.distinct()
.sort()
.zipWith(Flux.range(1, Integer.MAX_VALUE),
(string, count) -> String.format(“%2d. %s”, count, string));
manyLetters.subscribe(System.out::println);
}
Code 4
allLetters.subscribe(System.out::println);
}
Code 5
@Test
public void shortCircuit() {
Flux<String> helloPauseWorld =
Mono.just(“Hello”)
.concatWith(Mono.just(“world”)
.delaySubscriptionMillis(500));
helloPauseWorld.subscribe(System.out::println);
}
Code 6
1. a
2. b
...
18. r
19. t
20. u
...
25. z
Code 7
1. a
2. b
...
18. r
19. s
20. t
...
26. z
Code 8
1. a
2. b
...
18. r
19. s
20. t
...
26. z
In order to output the individual This adds the missing S just be- because the test terminates too
letters in the “quick brown fox” fore we filter out duplicates and early. In snippets and tests where
sentence, you also need flat- sort/count the letters: (Code 8) you only sort of write a main class
Map (as you did in “RxJava by Ex- like this, you’ll usually want to re-
ample”), but in Reactor, you use The previous article noted the vert to blocking behavior. To do
fromArray instead of from. You resemblance between the Rx vo- that, you could create a Count-
then want to filter out duplicate cabulary and the Java Streams DownLatch and call countDown
letters and sort what’s left over API and, in fact, when the data is in your subscriber (both in onEr-
using distinct and sort. Final- readily available from memory, ror and onComplete). But that’s
ly, you want to output an index Reactor, like Java Streams, acts not very reactive, is it? And what
for each distinct letter, which in simple push mode (see the if you forget to count down, be-
can be done using zipWith and backpressure section below to cause of error for instance?
range: (Code 4) understand why). More complex
and truly asynchronous snippets A second way to solve that issue
This helps us notice missing S, as wouldn’t work with this pattern is to use one of the operators
expected: (Code 7) of just subscribing in the main that revert to the non-reactive
thread, primarily because control world. Specifically, toIterable
One way of fixing that is to cor- would return to the main thread and toStream will both produce
rect the original words array, but and then exit the application as a blocking instance. Let’s use to-
we could also manually add the S soon as the subscription is done. Stream in an example: (Code 9)
value to the Flux of letters using For instance: (Code 6)
concat/concatWith and a Mono: As you would expect, this prints
(Code 5) This snippet prints “Hello” but “Hello”, pauses, then prints
fails to print the delayed “world” “world’ and terminates.
helloPauseWorld.toStream()
.forEach(System.out::println);
}
Code 9
@Test
public void firstEmitting() {
Mono<String> a = Mono.just(“oops I’m late”)
.delaySubscriptionMillis(450);
Flux<String> b = Flux.just(“let’s get”, “the party”, “started”)
.delayMillis(400);
Flux.firstEmitting(a, b)
.toIterable()
.forEach(System.out::println);
}
Code 10
<dependency>
<groupId>org.springframework.boot.experimental</groupId>
<artifactId>spring-boot-starter-web-reactive</artifactId>
</dependency>
Code 11
As we mentioned above, Reac- don’t want to wait four seconds es like Func1, Func2, Action0,
tor renamed RxJava’s amb() op- in a unit test! Fortunately, as we’ll Action1, etc. were required in-
erator to firstEmitting, which see in a later section, Reactor stead. In RxJava 2, these classes
more clearly hints at the opera- comes with powerful testing ca- mirror java.util.function
tor’s purpose: selecting the first pabilities that nicely cover this the way Reactor 2 used to do
Flux to emit. The following ex- case. when it still had to support Java
ample creates a Mono, delays it by 7.
450 ms, and creates a Flux that Having sampled how Reactor
emits its values with a 400 ms compares for a few common op- The Reactor API also embraces
pause before each value. When erators, let’s zoom back and have types introduced in Java 8. Most
firstEmitting() them togeth- a look at other differentiating as- of the time-related operators will
er, the first value from the Flux pects of the library. refer to durations (e.g. timeout,
comes in before the Mono val- interval, delay, etc.) so using
ue so it is the Flux that ends up the Java 8 Duration class is ap-
played. (Code 10) A Java 8 foundation propriate.
Reactor targets Java 8 rather
This prints each part of the sen- than previous Java versions. This The Java 8 Streams API and
tence with a 400-ms pause be- again aligns with the goal of re- CompletableFuture can also
tween each section. ducing the API surface: RxJava both be easily converted to a
targets Java 6 where there is no Flux/Mono and vice versa. But
At this point, you might wonder, java.util.function package you shouldn’t usually convert a
what if you’re writing a test for so you can’t take advantage of Stream to a Flux. The level of in-
a Flux that introduces delays classes like Function or Con- direction added by Flux or Mono
of 4000 ms instead of 400? You sumer. Specific, additional class- is a negligible cost when they
@GetMapping(“hello/{who}”)
public Mono<String> hello(@PathVariable String who) {
return Mono.just(who)
.map(w -> “Hello “ + w + “!”);
}
@GetMapping(“helloDelay/{who}”)
public Mono<String> helloDelay(@PathVariable String who) {
return reactiveLibrary.withDelay(“Hello “ + who + “!!”, 2);
}
@PostMapping(“heyMister”)
public Flux<String> hey(@RequestBody Mono<Sir> body) {
return Mono.just(“Hey mister “)
.concatWith(body
.flatMap(sir -> Flux.fromArray(sir.getLastName().split(“”)))
.map(String::toUpperCase)
.take(1)
).concatWith(Mono.just(“. how are you?”));
}
}
Code 12
completes when the Mono name to a greeting sentence that This returns the string “Hello mis-
completes. is returned to the client. ter T. How are you?”
• Non-reactive return types By doing a GET on /hello/Si- The reactive aspect of Spring
(void and T): These now mon we get “Hello Simon!” as a Data is also currently being de-
imply that your controller text response. veloped in the Kay release train,
method is synchronous, which for Spring Data Commons
but should be non-blocking The second endpoint is a bit is the 2.0.x branch. There is a first
(short-lived processing). more complicated: it asynchro- milestone build that you can
The request handling fin- nously receives a serialized Sir get by adding the Spring Data
ishes once the method is instance (a class simply made Kay-M1 bill of materials (BOM) to
executed. The returned T is up of a firstName and lastName your pom: (Code 13)
serialized back to the client attributes) and flatMaps it into a
asynchronously. stream of the last name’s letters. For this simplistic example, just
It then takes the first of these let- add the spring-data-commons
Here is a quick example of a ters, maps it to upper case and dependency in your pom (it will
plain-text @Controller that concatenates it into a greeting take the version from the BOM
uses the experimental web reac- sentence. above): (Code 14)
tive module: (Code 12)
So make the following JSON ob- Reactive support in Spring Data
The first endpoint takes a path ject POST to /heyMister: revolves around the new Reac-
variable, transforms it into a { tiveCrudRepository<T, ID>
Mono<String> and maps that “firstName”: “Paul”, interface, which extends Repos-
“lastName”: “tEsT” itory<T, ID>. This interface
}
@GetMapping(“data/{who}”)
public Mono<ResponseEntity<Sir>> hello(@PathVariable String who) {
return reactiveRepository.findOne(who)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.status(404).body(null));
}
}
Code 15
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.5.2</version>
<scope>test</scope>
</dependency>
Code 16
@Component
public class MyReactiveLibrary {
@Test
public void testAlphabet5LimitsToZ() {
MyReactiveLibrary library = new MyReactiveLibrary();
StepVerifier.create(library.alphabet5(‘x’))
.expectNext(“x”, “y”, “z”)
.expectComplete()
.verify();
}
Code 18
In Reactor, these two broad fea- implementation, making obso- cate or even consume onNext
tures are combined into the lete the need to explicitly pass events, allowing you to do more
StepVerifier class. It can be the scheduler to operators. The advanced interactions with the
found in the add-on module StepVerifier will then, if nec- value (like using an assertion
reactor-test from the reac- essary, configure the Flux/Mono library). Any AssertionError
tor-addons repository. You can created within the Supplier, thrown by one of these will be
initialize the StepVerifier by turning timed operators into “vir- reflected in the final verification
creating an instance from any tually timed” operators. You can result. Finally, call verify() to
Publisher, using the StepVer- then script stream expectations check your expectations; this will
ifier.create builder. For virtual and time progress: what the truly subscribe to the defined
time, you can use the StepVer- next elements should be, should source via StepVerifier.cre-
ifier.withVirtualTime build- there be an error, should it move ate or StepVerifier.withVir-
er, which takes a Supplier<- forward in time, etc. tualTime.
Publisher>. This will create a
VirtualTimeScheduler and Other methods include verifying Let’s take a few simple examples
enable it as the default scheduler that data match a given Predi- and demonstrate how StepVer-
@Test
public void testWithDelay() {
MyReactiveLibrary library = new MyReactiveLibrary();
Duration testDuration =
StepVerifier.withVirtualTime(() -> library.withDelay(“foo”, 30))
.expectSubscription()
.thenAwait(Duration.ofSeconds(10))
.expectNoEvent(Duration.ofSeconds(10))
.thenAwait(Duration.ofSeconds(10))
.expectNext(“foo”)
.expectComplete()
.verify();
System.out.println(testDuration.toMillis() + “ms”);
}
Code 21
ifier works. For these snippets, emits a given value after a given It turns out that both of these
you’ll want to add the following delay (in seconds). tests fail. A look at the StepVer-
test dependencies to your pom: ifier output of each case may
(Code 16) The first test to write ensures that help you spot the bug. (Code 20)
calling alphabet5 from X limits
First, imagine you have reactive the output to X, Y, and Z. With So it looks like this method
class called MyReactiveLibrary StepVerifier it would go like this: doesn’t stop at Z but continues
that produces a few instances of (Code 18) emitting characters along the
Flux that you want to test. (Code ASCII range. We could fix that by
17) The second test to run on alpha- adding a .take(Math.min(5,
bet5 is that every returned value ‘z’ - from + 1)), for instance,
The first method is intended to is an alphabetical character. For or using the same Math.min as
return five letters of the alpha- that we’d like to use a rich asser- the second argument to range.
bet following (and including) tion library like AssertJ: (Code 19)
the given starting letter. The sec- The last test to make involves
ond method returns a Flux that manipulating virtual time: you’ll
@Override
public void error(Throwable e) {
emitter.error(e);
}};
feed.register(listener);
}, FluxSink.OverflowStrategy.BUFFER);
test the delaying method with- but would block for the provided chronous corner cases and let
out actually waiting for the giv- duration. you focus on emitting your val-
en amount of seconds by using ues.
the withVirtualTime builder: StepVerifier comes with many
(Code 21) more methods for describing Use Flux.create and get a
expectations and asserting the FluxSink in the callback that
This tests a Flux that would be state of a Publisher (and if you you can use to emit data via
delayed by 30 seconds in the sce- think about new ones, contribu- next. This custom Flux can be
nario of an immediate subscrip- tions and feedback are always cold; in order to make it hot, you
tion followed by three periods welcome in the GitHub reposito- can use publish() and con-
of 10 seconds in which nothing ry). nect(). Building on the example
happens, an onNext(“foo”), from the previous article with a
and completion. feed of price ticks, we get an al-
Custom hot source most verbatim translation in Re-
The System.out output prints The concepts of hot and cold Ob- actor. (Code 22)
the duration of the verification servables discussed at the end
process (which in my latest run of “RxJava by Example” also apply Before connecting to the
was 8 ms).Note that when using to Reactor. hot Flux, why not subscribe
the create builder instead, the twice? One subscription will
thenAwait and expectNoEvent To create a custom Flux, instead print the detail of each tick while
methods would still be available of the RxJava AsyncEmitter the other will only print the in-
class, you’d use Reactor’s Flux- strument. (Code 23)
Sink. This will cover all the asyn-
Conclusion
Reactor builds on the Rx language but targets
Java 8 and the RS specification. Concepts you
might have learned in RxJava also apply to Re-
actor, despite a few API differences. If you want
to dig deeper into Reactor, try the snippets
presented in this article, which are available in
a GitHub repository. There is also a Lite Rx API
Hands-On workshop that covers more opera-
tors and use cases.
36
Read online on InfoQ
Refactoring to Reactive:
Anatomy of a JDBC Migration
Nicolae Marasoiu is a passionate software developer with years of experience building high-
performance server-side applications for product and outsourcing companies, from start-ups
to well-established firms. He enjoys contributing in many areas of product development and
inspiring teams in their technical adventures.
This article will transform a real level of abstraction, immuta- actual number of available
(intentionally simple) legacy ap- bility, and fluent style. For ex- threads, while still allowing
plication (with a classic setup ample, the Function<T,Ob- the code to execute concur-
consisting of a web server and servable<U>> type is rently instead of queuing in
database back end), to a reactive composable, because we can some thread pool.
model, striving for a threefold chain together multiple such
benefit: functions using the flatMap We will do this by having the
operator of the Observable. application react as soon
1. Working in a functional style as it receives each chunk of
will allow us to compose our 2. Building a more resilient ap- information from the data-
code and thus reuse it, while plication allows our server base rather than having the
rendering it clearer and more to sustain a greater number thread wait for that infor-
readable thanks to a higher of concurrent users than the mation. This is a transforma-
tion from a pull mechanism on its journey to its new func- it as a delegating method to a
(doing blocking I/O) to a tional and reactive form. new method that contains the
push mechanism that con- implementation to return an
tinues execution when data Once the tests are done, we can Observable<T>. The delegat-
becomes available or some start with the first refactoring ing method (with the original
event occurs, such as a time- step: replacing method return method signature) calls toB-
out or an exception. types with Observable, Single, locking on the Observable, to
or Completable, all part of RxJa- enforce the original synchronous
3. Building a more respon- va. Specifically, for each method contract, before returning any
sive application allows our that returns a value of type T, we values. Starting as small as possi-
browser view to update even can return Single<T>, an Ob- ble is a great migration strategy
as the first bytes start com- servable<T> with exactly one that helps overcome the learning
ing back from the database. value to emit, or an error. For curve and deliver steady incre-
This is achievable with the List<T>, we will change the re- mental progress. We can apply
streaming Servlet 3.1 API and turn type to Observable<T>, incremental refactoring with Rx-
will become available with while for each void method, Java.
Spring Reactor and the asso- we will return Completable,
ciated web extensions on the which can be converted to Sin- Here is a concrete example. We
Spring stack. gle<Void>. can see all of the code and its his-
tory here, where I take a classical
The examples in this article may Rather than replace all method Spring application tkssharma/
be downloaded from this link. return types in all the layers at Spring-JDBC and convert it to Rx-
the same time, let’s select one Java in two ways: using the RxJD-
We want to endow our program layer and start there. Convert- BC library (in the rx-jdbc branch)
with its new reactive makeover ing a method that returns T into and using the PgAsync library (in
in small steps, using incremental one that returns Single<T>, pgasync branch).
refactoring. one returning List<T> to an
Observable<T>, or a void to Let’s look at the following meth-
Before we start, let’s enrich our a Completable does not need ods from the Spring-JDBC proj-
test suite for the legacy appli- to change that method as it is ect: (Code 1)
cation, because we rely on such known by its client code: instead,
tests for the correctness of the re- we can retain the method’s orig- Following the above migration
factored versions of the program inal signature, but implement strategy, we will retain these
<dependency>
<groupId>com.github.davidmoten</groupId>
<artifactId>rxjava-jdbc</artifactId>
<version>0.7.2</version>
</dependency>
Code 8
Here is the getStudents imple- actions, which typically contain This Transaction object will be
mentation again, this time with multiple statements. passed from Java closure to Java
the PgAsync library. (Code 9) closure, as we see above: first,
Here is how a transaction would transaction is available as an
To use the PgAsync library, im- look: (Code 11) argument to the flatMap opera-
port this Maven dependency: tor. There, it is used in three spots:
(Code 10) This is a single-statement trans-
action, but it illustrates how we 1. First, it launches the DML
At this moment we have a tru- can do transactions in an async statement within the trans-
ly reactive (asynchronous, reactive API. Transaction be- action. Here, the result of
event-driven, non-blocking) gin, commit, and rollback are the querySet operation that
back-end implementation. We all monadic functions: they re- executes the DML is also an
also have an end-to-end asyn- turn an Observable and can be Observable that holds the
chronous solution that allows chained with flatMap. result of the DML (general-
us to process more user actions ly a Row with updated row
concurrently (at the I/O flows Let’s travel through the example counts), and is further trans-
level) than actual threads in the above, starting with the signa- formed with flatMap to an-
JVM. ture. The dml execution function other Observable.
takes a DML statement like UP-
Next, let’s work on transactions. DATE or INSERT, along with any 2. The second flatMap then
We will take a scenario where we parameters, and schedules it for uses our transaction object
want to modify data using da- execution. Note that db.begin to commit the transaction.
ta-manipulation-language (DML) returns Observable<Trans- There, the transaction vari-
operations INSERT or UPDATE. In- action>. The transaction is not able is enclosed by a lambda
troducing asynchronicity is com- created right away because it function and is provided as
plicated even for the simplest involves database I/O. So this is an argument to this second
transaction consisting of a single an asynchronous operation such flatMap. This is one way we
DML statement, since we are so that when execution completes, can send data from one part
used to transactions that block it returns a Transaction object of an async flow to anoth-
threads. And it’s even more com- on which SQL queries followed er: using a variable from the
plicated for more realistic trans- by commit or rollback can sub- lexical scope and using it in
sequently be called as required. a lambda expression creat-
Markus Eisele is a Java Champion, former Java EE Expert Group member, founder of JavaLand,
reputed speaker at Java conferences around the world, and a very well-known figure in the
Enterprise Java world. He works as a developer advocate at Lightbend. Find him on Twitter @
myfear.
While the term “reactive” has been around for a long time, only recently
has the industry recognized it as the de facto way forward in system
design, leading to its mainstream adoption. In 2014, Gartner wrote that
the three-tier architecture that used to be so popular was beginning
to show its age. This has become even clearer with the ongoing
modernization efforts driven by enterprise, which has had to start
rethinking the way developers have learned to build applications for
more than a decade.
Microservices are taking the application design and imple- liths; the real value lies in better
software industry by storm and mentation has been forging its resources consumption and ex-
the shock waves are shaking the way through IT systems with treme scalability for unpredict-
traditional development work- unprecedented momentum. able workloads. The traits of the
flow to the core. We’ve seen soft- And even if the term “microser- Reactive Manifesto are quickly
ware-design paradigms change vices” isn’t completely new, our becoming the new Bible for mi-
and project-management meth- industry is realizing that it’s not croservices-based architectures,
odologies evolve — but the only about coupling RESTful as they are essentially distributed
consequent shift towards new endpoints and slicing mono- reactive applications.
The actor model in concurrency and for increasing Actors with Java 8 and
today’s applications resource efficiency. Importantly, Akka
Applications must be highly the actor model also has well-de- Akka is a toolkit and runtime
responsive to retain user inter- fined ways to gracefully handle for building highly concurrent,
est and must evolve quickly to errors and failures, ensuring a distributed, and resilient mes-
remain relevant to meet the level of resilience that isolates is- sage-driven applications on the
ever-changing needs and ex- sues and prevents cascading fail- JVM. Akka’s “actors” allow you to
pectations of the audience. The ures and massive downtime. write concurrent code without
technologies available for build- having to think about low-lev-
ing applications continue to In the past, building highly con- el threads and locks. Other tools
evolve at a rapid pace; science current systems typically in- include Akka Streams and the
has evolved, and the emerging volved a great deal of low-level Akka HTTP layer. Although Akka
requirements cannot rely on wiring and technical program- is written in Scala, there is a Java
yesterday’s tools and method- ming techniques that were dif- API, too. The following examples
ologies. The actor model is one ficult to master. These technical work with Akka 2.4.9 and above
concept that has emerged as an challenges competed for atten- — but the Java with lambda
effective tool for building sys- tion with the core business func- support part of Akka has been
tems that take advantage of the tionality of the system because considered experimental as of its
processing power harnessed by much of the effort had to be fo- introduction in Akka 2.3.0 so ex-
multicore, in-memory, clustered cused on the functional details, pect it to change until its official
environments. requiring a considerable amount release.
of time and effort for plumb-
The actor model provides a rela- ing and wiring. When building The actor is the basic unit of work
tively simple but powerful model systems with actors, things are in Akka. An actor is a container
for designing and implementing done at a higher level of abstrac- for state and behavior, and can
applications that can distribute tion because the plumbing and create and supervise child actors.
and share work across all sys- wiring are already built into the Actors interact with each other
tem resources — from threads actor model. Not only does this through asynchronous messag-
and cores to clusters of servers liberate us from the gory details es, which are processed synchro-
and data centers. It provides an of traditional system implemen- nously, one message at a time.
effective framework for building tation, it also allows for more fo- This model protects an actor’s in-
applications with high levels of cus on core system functionality ternal state, makes it thread safe,
and innovation.
{
receive(ReceiveBuilder
.match(Message.class, this::onMessage)
.build()
);
}
}
Code 3
and implements event-driven An actor’s initial behavior is de- additional information about
behavior that won’t block other fined by implementing the re- how to start the actor. The akka.
actors. To get started, you don’t ceive() method with the help of actor.Props is a configuration ob-
need much more than the Akka a ReceiveBuilder in the default ject that is used to expose pieces
Maven dependency. (Code 1) constructor. receive() matches in- of context-scoped configuration
coming messages and executes to all pieces of the framework. It
related behavior. The behavior is used in creating our actors; it
Changing actor state for each message is defined us- is immutable so it is thread-safe
Just like we exchange text mes- ing a lambda expression. In the and fully shareable.
sages on mobile devices, we use following example, the Receive- return Props.
messages to invoke an actor. And Builder uses a reference to the in- create(Counter.
also like text messages, the mes- terface method onMessage. The class);
sages between actors must be onMessage method increases a
immutable. The most important counter (internal state) and logs The Props object describes the
part of working with an actor an info message via the Abstract- constructor arguments of the
is to define the messages it can LoggingActor.log method. (Code actor. It is a good practice to en-
receive. (The message is also 2) capsulate it in a factory function
commonly referred to as “proto- that is closer to the actor’s con-
col” because it defines the point With the actor in place, we need structor. The ActorSystem itself
of interaction between actors.) to start it. This is done via the is created in the main method.
Actors receive messages and re- ActorSystem, which controls the (Code 3)
act to them. They can send other lifecycle of the actors inside it.
messages, change their state or But first, we need to supply some
behavior, and create other actors.
// ...
}
Code 6
private final String password;
public Alarm(String password) {
this.password = password;
// ...
}
Code 7
public static Props props(String password) {
return Props.create(Alarm.class, password);
}
Code 8
Both ActorSystem (“sample1”) safety. Messages that are sent to without the correct password, it
and the contained actor “count- actors from different threads are will sound. As an actor, the alarm
er” receive names for navigating shielded from concurrency prob- can react to three messages:
actor hierarchies (more on these lems since the actor framework disable, enable with a password
later). Now the ActorRef can send serializes the message process- (supplied as a payload), and tam-
a message to the actor, for exam- ing. You can find the complete pering. All of them go into the
ple: (Code 4) example online. contract. (Code 6)
Here, the two parameters define The actor gets a preset attribute
the message to be sent and the Changing actor behavior for the password, which is also
sender of the message. (As the You will notice that our simple passed into the constructor.
name implies, noSender indi- example modified the actor state (Code 7)
cates that the sender isn’t used but did not change its behavior,
in this case.) If you run the above and it never sent messages to The aforementioned akka.actor.
example, you get the expected other actors. Consider the case Props configuration object also
output: (Code 5) of a burglar alarm: we can enable needs to know about the pass-
and disable it with a password word attribute in order to pass it
This is a simple example yet it and its sensor detects activity. If a to the actual constructor when
supplies all of our desired thread burglar tries to disable the alarm the actor system starts. (Code 8)
enabled = ReceiveBuilder
.match(Activity.class, this::onActivity)
.match(Disable.class, this::onDisable)
.build();
disabled = ReceiveBuilder
.match(Enable.class, this::onEnable)
.build();
receive(disabled);
}
}
Code 10
The Alarm actor also needs a Note that the call to receive at short warning. The message pay-
behavior for each possible mes- the end sets the default behavior load now contains the password
sage. These behaviors are imple- to “disabled”. All three behaviors that we can access to validate it.
mentations of the receive meth- are implemented using three (Code 12)
od of AbstractActor. The receive existing methods (onActivity,
method should define a series of onDisable, and onEnable). The When it receives a disable mes-
match statements (each of type easiest of these methods to work sage, the actor needs to check
PartialFunction<Object, Boxe- on is onActivity. If there is activi- the password, log a short mes-
dUnit>) that define the messag- ty, the alarm logs a string to the sage about the changed state,
es the actor can handle and the console. Note that there is no and actually change the state
implementation of how to pro- message payload required for ac- to disabled or log a warning
cess the messages. (Code 9) tivity so we just give it the name message that the password was
“ignored”. (Code 11) wrong. (Code 13)
If this signature seems fright-
ening, our code can effectively If the actor receives an enable That completes the actor logic.
sweep it under the rug by using a message, the new state will be We are ready to start the actor
ReceiveBuilder that can be used logged to the console and the system and send it a couple of
as shown earlier. (Code 10) state changed to enabled. If the messages. Note that our secret
password doesn’t match, it logs a password “cat” is passed as a
property to the actor system. Actor hierarchies that it will not process normal
(Code 14) Actors may create other actors. messages until resumed) and no-
When one actor creates another tifies its supervisor of the failure.
Let’s send these messages: (Code actor, the creator is known as the
15) “supervisor” and the created ac- So far, we’ve created actors and
tor is known as the “worker”. Su- assigned them names. Actor
They produce the following out- pervisors may create worker ac- names are used to identify ac-
put: (Code 16) tors for many reasons, the most tors in the hierarchy. The actor
common of which is to delegate that generally interacts the most
You can find the complete work- work to them. with others is the parent of all
ing example online. user-created actors, the guard-
The supervisor also becomes a ian with the path /user. Actors
Until now, we’ve only used indi- caretaker of the workers. Just as created with the primordial sys-
vidual actors to process messag- a parent watches over his or her tem.actorOf() are direct children
es — but like in a business, actors children, the supervisor tends of this guardian and when it ter-
form natural hierarchies. to the wellbeing of its workers. minates, all normal actors in the
If a worker runs into a problem, system will shut down as well.
it suspends itself (which means In the above alarm example, we
Inside of an actor, you can call • Resume the child, keeping the so-called supervision strat-
getContext().actorO f(props, its accumulated internal state egy. Akka provides two classes
“alarm-child”) to create a new ac- but ignoring the message of supervision strategies: One-
tor named alarm-child as a child that lead to the failure. ForOneStrategy and AllForOneS-
of the alarm actor . The child life- trategy. The former applies the
cycle is bound to the supervising • Restart the child, clearing out obtained directive only to the
actor, which means that if you its accumulated internal state failed child whereas the latter
stop the “alarm” actor, it will also by starting a new instance. applies it to all siblings as well.
stop the child. (Figure 1) Normally, you should use the
• Stop the child permanently OneForOneStrategy, which is the
This hierarchy also has a sig- and send all future messages default if none is explicitly spec-
nificant influence on how ac- for the child to the dead-letter ified. It is defined by overriding
tor-based systems handle fail- box. the SupervisorStrategy method.
ures. The quintessential feature (Code 19)
of actor systems is that tasks are • Escalate the failure, thereby
split up and delegated until they failing the supervisor itself. The first parameter defines the
become small enough to be han- maxNrOfRetries, which is the
dled in one piece. In doing so, not Let’s examine this with an ex- number of times a child actor
only is the task itself clearly struc- ample: A NonTrustWorthyChild may restart before the Super-
tured but the resulting actors can receives Command messages visor stops it (a negative value
be reasoned about in terms of: and increases an internal counter indicates no limit). The withinTi-
with each message. If the mes- meRange parameter defines the
• which messages they should sage count is divisible by four, duration of the window for max-
process, it throws a RuntimeException, NrOfRetries. As defined above,
which it escalates to the Super- the strategy is to try 10 times
• how they should react nor- visor. There’s nothing really new within 10 seconds. The Decider-
mally, and here, as the command message Builder works exactly as the Re-
has no payload. (Code 17) ceiveBuilder to define matches
• how failures should be han- on occurring exceptions and
dled. The Supervisor starts the Non- how to react to them. In this case,
TrustWorthyChild in its construc- if there are 10 retries within 10
If one actor does not have the tor and forwards all command seconds the Supervisor stops the
means for dealing with a cer- messages that it receives directly NonTrustWorthyChild and sends
tain situation, it sends a corre- to the child. (Code 18) all remaining messages to the
sponding failure message to its dead-letter box.
supervisor, asking for help. The When the Supervisor actor starts,
supervisor has four options for the resulting hierarchy will be / The actor system is started with
reacting to a failure: user/supervisor/child. Before this the Supervisor actor. (Code 20)
can be done, we need to define
{
receive(ReceiveBuilder
.match(Command.class, this::onCommand)
.build()
);
}
receive(ReceiveBuilder
.matchAny(command -> child.forward(command, getContext()))
.build()
);
}
//…
}
Code 18
@Override
public SupervisorStrategy supervisorStrategy() {
return new OneForOneStrategy(
10,
Duration.create(10, TimeUnit.SECONDS),
DeciderBuilder
.match(RuntimeException.class, ex -> stop())
.build()
);
}
Code 19
The output shows that after four measure downtime not in hours basic level with the asynchro-
messages, the exception esca- but seconds. Actor-based sys- nous exchange of messages be-
lates to the Supervisor and the tems allow us to create quickly tween actors. If you send me a
remaining messages are sent to evolving microservice architec- message, you have to consider
the deadLetters box. If the Su- tures that can scale and run with- the possible outcomes: what do
pervisorStrategy would have out stopping. you do when you get the reply
been defined to restart() instead you expect… or don’t!? This goes
of stop(), the Supervisor would It’s the actor model that provides all the way towards implement-
have started a new instance of the core functionality of reactive ing strategies for handling nodes
the NonTrustWorthyChild actor systems, defined in the Reactive that leave and join a cluster.
instead. (Code 21) Manifesto as responsive, resil-
ient, elastic, and message driven. Thinking in terms of actors is in
We can turn off or adjust this log- many ways much more intuitive
ging with configuration settings The fact that actor systems can for us when designing systems.
akka.log-dead-letters and akka. scale horizontally, from a sin- The way actors interact is more
log-dead-letters-during-shut- gle node to clusters with many natural to us since it has, on a
down. nodes, provides us with the flex- simplistic level, much in com-
ibility to scale our systems for mon with how humans interact.
You can follow up with the com- massive load. It is also possible to This allows us to design and im-
plete example online and play implement systems with the ca- plement systems in ways that let
around with the SupervisorStrat- pability to scale elastically — that us focus more on the core func-
egy. is, scale the capacity of systems, tionality of the systems and less
either manually or automatically, on the plumbing.
to adequately support the peaks
Summary and valleys of system activity.
With Akka and Java 8, it is now
possible to create distributed, With actors and actor systems,
microservices-based systems failure detection and recovery
that just a few years ago were is an architectural feature, not
the stuff of dreams. Enterprises something that can be patched
across all industries now desire on later. Out of the box, we get
the ability to create systems that actor-supervision strategies for
can evolve at the speed of the handling problems with subor-
business and cater to the whims dinate worker actors up to the
of users. We can now elastically actor-system level, with clusters
scale systems that support mas- of nodes that actively monitor
sive numbers of users and pro- the state of the cluster — where
cess huge volumes of data. We dealing with failures is baked
can now harden systems with into the DNA of actors and actor
a level of resilience that lets us systems. This starts at the most
46
Architectures You’ve
Always Wondered About
45
A Preview of C# 7
44
distributed computations, time series databases to what it
takes to transition to a NoSQL database solution. Cloud Lock-In