better Typed HelloWorld, #24491
* single actor hello world is too unrealistic and shows the wrong things * although this is longer I think it's better java and feedback
This commit is contained in:
parent
4b54941947
commit
054573e7e1
7 changed files with 182 additions and 117 deletions
|
|
@ -51,9 +51,9 @@ message.
|
|||
|
||||
The behavior of the Actor is defined as the `greeter` value with the help
|
||||
of the `receive` behavior factory. Processing the next message then results
|
||||
in a new behavior that can potentially be different from this one. State is
|
||||
updated by returning a new behavior that holds the new immutable state. In this
|
||||
case we don't need to update any state, so we return `Same`, which means
|
||||
in a new behavior that can potentially be different from this one. State is
|
||||
updated by returning a new behavior that holds the new immutable state. In this
|
||||
case we don't need to update any state, so we return `same`, which means
|
||||
the next behavior is "the same as the current one".
|
||||
|
||||
The type of the messages handled by this behavior is declared to be of class
|
||||
|
|
@ -73,6 +73,31 @@ protocol but Actors can model arbitrarily complex protocols when needed. The
|
|||
protocol is bundled together with the behavior that implements it in a nicely
|
||||
wrapped scope—the `HelloWorld` @scala[object]@java[class].
|
||||
|
||||
As Carl Hewitt said, one Actor is no Actor—it would be quite lonely with
|
||||
nobody to talk to. We need another Actor that that interacts with the `greeter`.
|
||||
Let's make a `bot` that receives the reply from the `greeter` and sends a number
|
||||
of additional greeting messages and collect the replies until a given max number
|
||||
of messages have been reached.
|
||||
|
||||
Scala
|
||||
: @@snip [IntroSpec.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/IntroSpec.scala) { #hello-world-bot }
|
||||
|
||||
Java
|
||||
: @@snip [IntroSpec.scala]($akka$/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/IntroTest.java) { #hello-world-bot }
|
||||
|
||||
Note how this Actor manages the counter by changing the behavior for each `Greeted` reply
|
||||
rather than using any variables.
|
||||
|
||||
|
||||
|
||||
A third actor spawns the `greeter` and the `bot` and starts the interaction between those.
|
||||
|
||||
Scala
|
||||
: @@snip [IntroSpec.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/IntroSpec.scala) { #hello-world-main }
|
||||
|
||||
Java
|
||||
: @@snip [IntroSpec.scala]($akka$/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/IntroTest.java) { #hello-world-main }
|
||||
|
||||
Now we want to try out this Actor, so we must start an ActorSystem to host it:
|
||||
|
||||
Scala
|
||||
|
|
@ -81,58 +106,29 @@ Scala
|
|||
Java
|
||||
: @@snip [IntroSpec.scala]($akka$/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/IntroTest.java) { #hello-world }
|
||||
|
||||
After importing the Actor’s protocol definition we start an Actor system from
|
||||
the defined `greeter` behavior.
|
||||
We start an Actor system from the defined `main` behavior and send two `Start` messages that
|
||||
will kick-off the interaction between two separate `bot` actors and the single `greeter` actor.
|
||||
|
||||
As Carl Hewitt said, one Actor is no Actor—it would be quite lonely with
|
||||
nobody to talk to. In this sense the example is a little cruel because we only
|
||||
give the `HelloWorld` Actor a fake person to talk to—the “ask” pattern
|
||||
(represented by the `?` operator) can be used to send a message such that the
|
||||
reply fulfills a @scala[`Promise` to which we get back the corresponding `Future`]@java[`CompletionStage`].
|
||||
The console output may look like this:
|
||||
|
||||
@@@ div {.group-scala}
|
||||
|
||||
Note that the `Future` that is returned by the “ask” operation is
|
||||
properly typed already, no type checks or casts needed. This is possible due to
|
||||
the type information that is part of the message protocol: the `?` operator
|
||||
takes as argument a function that accepts an `ActorRef[U]` (which
|
||||
explains the `_` hole in the expression on line 7 above) and the `replyTo`
|
||||
parameter which we fill in is of type `ActorRef[Greeted]`, which
|
||||
means that the value that fulfills the `Promise` can only be of type
|
||||
`Greeted`.
|
||||
|
||||
@@@
|
||||
|
||||
@@@ div {.group-java}
|
||||
|
||||
Note that the `CompletionStage` that is returned by the “ask” operation is
|
||||
properly typed already, no type checks or casts needed. This is possible due to
|
||||
the type information that is part of the message protocol: the `ask` operator
|
||||
takes as argument a function that pass an `ActorRef<U>`, which is the
|
||||
`replyTo` parameter of the `Greet` message, which means that when sending
|
||||
the reply message to that `ActorRef` the message that fulfills the
|
||||
`CompletionStage` can only be of type `Greeted`.
|
||||
|
||||
@@@
|
||||
|
||||
We use this here to send the `Greet` command to the Actor and when the
|
||||
reply comes back we will print it out and tell the actor system to shut down.
|
||||
|
||||
@@@ div {.group-scala}
|
||||
|
||||
The `recovery` combinator on the original `Future` is
|
||||
needed in order to ensure proper system shutdown even in case something went
|
||||
wrong; the `flatMap` and `map` combinators that the `for` expression gets
|
||||
turned into care only about the “happy path” and if the `future` failed with
|
||||
a timeout then no `greeting` would be extracted and nothing would happen.
|
||||
|
||||
@@@
|
||||
|
||||
In the next section we demonstrate this on a more realistic example.
|
||||
```
|
||||
[INFO] [03/13/2018 15:50:05.814] [hello-akka.actor.default-dispatcher-4] [akka://hello/user/greeter] Hello World!
|
||||
[INFO] [03/13/2018 15:50:05.815] [hello-akka.actor.default-dispatcher-4] [akka://hello/user/greeter] Hello Akka!
|
||||
[INFO] [03/13/2018 15:50:05.815] [hello-akka.actor.default-dispatcher-2] [akka://hello/user/World] Greeting 1 for World
|
||||
[INFO] [03/13/2018 15:50:05.815] [hello-akka.actor.default-dispatcher-4] [akka://hello/user/Akka] Greeting 1 for Akka
|
||||
[INFO] [03/13/2018 15:50:05.815] [hello-akka.actor.default-dispatcher-5] [akka://hello/user/greeter] Hello World!
|
||||
[INFO] [03/13/2018 15:50:05.815] [hello-akka.actor.default-dispatcher-5] [akka://hello/user/greeter] Hello Akka!
|
||||
[INFO] [03/13/2018 15:50:05.815] [hello-akka.actor.default-dispatcher-4] [akka://hello/user/World] Greeting 2 for World
|
||||
[INFO] [03/13/2018 15:50:05.815] [hello-akka.actor.default-dispatcher-5] [akka://hello/user/greeter] Hello World!
|
||||
[INFO] [03/13/2018 15:50:05.815] [hello-akka.actor.default-dispatcher-4] [akka://hello/user/Akka] Greeting 2 for Akka
|
||||
[INFO] [03/13/2018 15:50:05.816] [hello-akka.actor.default-dispatcher-5] [akka://hello/user/greeter] Hello Akka!
|
||||
[INFO] [03/13/2018 15:50:05.816] [hello-akka.actor.default-dispatcher-4] [akka://hello/user/World] Greeting 3 for World
|
||||
[INFO] [03/13/2018 15:50:05.816] [hello-akka.actor.default-dispatcher-6] [akka://hello/user/Akka] Greeting 3 for Akka
|
||||
```
|
||||
|
||||
## A More Complex Example
|
||||
|
||||
The next example demonstrates some important patterns:
|
||||
The next example is more realistic and demonstrates some important patterns:
|
||||
|
||||
* Using a sealed trait and case class/objects to represent multiple messages an actor can receive
|
||||
* Handle sessions by using child actors
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue