New type StatusReply simplifies the very common use case of replying to a request with either a successful reply or an error reply which can be repetitive to define for every actor, with the additional overhead of having to make sure each such sealed top type + 2 concrete reply classes has working serialization.
This commit is contained in:
parent
ec08c9dde4
commit
996f424835
43 changed files with 2093 additions and 324 deletions
|
|
@ -160,7 +160,9 @@ The adapter function is running in the receiving actor and can safely access its
|
|||
|
||||
In an interaction where there is a 1:1 mapping between a request and a response we can use `ask` on the `ActorContext` to interact with another actor.
|
||||
|
||||
The interaction has two steps, first we need to construct the outgoing message, to do that we need an @scala[`ActorRef[Response]`]@java[`ActorRef<Response>`] to put as recipient in the outgoing message. The second step is to transform the successful `Response` or failure into a message that is part of the protocol of the sending actor.
|
||||
The interaction has two steps, first we need to construct the outgoing message, to do that we need an @scala[`ActorRef[Response]`]@java[`ActorRef<Response>`] to put as recipient in the outgoing message.
|
||||
The second step is to transform the successful `Response` or failure into a message that is part of the protocol of the sending actor.
|
||||
See also the [Generic response wrapper](#generic-response-wrapper) for replies that are either a success or an error.
|
||||
|
||||
**Example:**
|
||||
|
||||
|
|
@ -212,7 +214,7 @@ Java
|
|||
Note that validation errors are also explicit in the message protocol. The `GiveMeCookies` request can reply
|
||||
with `Cookies` or `InvalidRequest`. The requestor has to decide how to handle an `InvalidRequest` reply. Sometimes
|
||||
it should be treated as a failed @scala[`Future`]@java[`Future`] and for that the reply can be mapped on the
|
||||
requestor side.
|
||||
requestor side. See also the [Generic response wrapper](#generic-response-wrapper) for replies that are either a success or an error.
|
||||
|
||||
Scala
|
||||
: @@snip [InteractionPatternsSpec.scala](/akka-actor-typed-tests/src/test/scala/docs/akka/typed/InteractionPatternsSpec.scala) { #standalone-ask-fail-future }
|
||||
|
|
@ -230,6 +232,50 @@ Java
|
|||
* There can only be a single response to one `ask` (see @ref:[per session child Actor](#per-session-child-actor))
|
||||
* When `ask` times out, the receiving actor does not know and may still process it to completion, or even start processing it after the fact
|
||||
|
||||
## Generic response wrapper
|
||||
|
||||
In many cases the response can either be a successful result or an error (a validation error that the command was invalid for example).
|
||||
Having to define two response classes and a shared supertype for every request type can be repetitive, especially in a cluster context
|
||||
where you also have to make sure the messages can be serialized to be sent over the network.
|
||||
|
||||
To help with this a generic status-response type is included in Akka: @apidoc[StatusReply], everywhere where `ask` can be used
|
||||
there is also a second method `askWithStatus` which, given that the response is a `StatusReply` will unwrap successful responses
|
||||
and help with handling validation errors. Akka includes pre-built serializers for the type, so in the normal use case a clustered
|
||||
application only needs to provide a serializer for the successful result.
|
||||
|
||||
For the case where the successful reply does not contain an actual value but is more of an acknowledgment there is a pre defined
|
||||
@scala[`StatusReply.Ack`]@java[`StatusReply.ack()`] of type @scala[`StatusReply[Done]`]@java[`StatusReply<Done>`].
|
||||
|
||||
Errors are preferably sent as a text describing what is wrong, but using exceptions to attach a type is also possible.
|
||||
|
||||
**Example actor to actor ask:**
|
||||
|
||||
Scala
|
||||
: @@snip [InteractionPatternsSpec.scala](/akka-actor-typed-tests/src/test/scala/docs/akka/typed/InteractionPatternsSpec.scala) { #actor-ask-with-status }
|
||||
|
||||
Java
|
||||
: @@snip [InteractionPatternsTest.java](/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/InteractionPatternsAskWithStatusTest.java) { #actor-ask-with-status }
|
||||
|
||||
A validation error is turned into a `Failure` for the message adapter. In this case we are explicitly handling the valdation error separately from
|
||||
other ask failures.
|
||||
|
||||
**Example ask from the outside:**
|
||||
|
||||
Scala
|
||||
: @@snip [InteractionPatternsSpec.scala](/akka-actor-typed-tests/src/test/scala/docs/akka/typed/InteractionPatternsSpec.scala) { #standalone-ask-with-status }
|
||||
|
||||
Java
|
||||
: @@snip [InteractionPatternsTest.java](/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/InteractionPatternsAskWithStatusTest.java) { #standalone-ask-with-status }
|
||||
|
||||
Note that validation errors are also explicit in the message protocol, but encoded as the wrapper type, constructed using @scala[`StatusReply.Error(text)`]@java[`StatusReply.error(text)`]:
|
||||
|
||||
Scala
|
||||
: @@snip [InteractionPatternsSpec.scala](/akka-actor-typed-tests/src/test/scala/docs/akka/typed/InteractionPatternsSpec.scala) { #standalone-ask-with-status-fail-future }
|
||||
|
||||
Java
|
||||
: @@snip [InteractionPatternsTest.java](/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/InteractionPatternsAskWithStatusTest.java) { #standalone-ask-with-status-fail-future }
|
||||
|
||||
|
||||
## Ignoring replies
|
||||
|
||||
In some situations an actor has a response for a particular request message but you are not interested in the response. In this case you can pass @scala[`system.ignoreRef`]@java[`system.ignoreRef()`] turning the request-response into a fire-and-forget.
|
||||
|
|
|
|||
|
|
@ -386,8 +386,13 @@ The @ref:[Request-Response interaction pattern](interaction-patterns.md#request-
|
|||
persistent actors, because you typically want to know if the command was rejected due to validation errors and
|
||||
when accepted you want a confirmation when the events have been successfully stored.
|
||||
|
||||
Therefore you typically include a @scala[`ActorRef[ReplyMessageType]`]@java[`ActorRef<ReplyMessageType>`] in the
|
||||
commands. After validation errors or after persisting events, using a `thenRun` side effect, the reply message can
|
||||
Therefore you typically include a @scala[`ActorRef[ReplyMessageType]`]@java[`ActorRef<ReplyMessageType>`]. If the
|
||||
command can either have a successful response or a validation error returned, the generic response type @scala[`StatusReply[ReplyType]]`]
|
||||
@java[`StatusReply<ReplyType>`] can be used. If the successful reply does not contain a value but is more of an acknowledgement
|
||||
a pre defined @scala[`StatusReply.Ack`]@java[`StatusReply.ack()`] of type @scala[`StatusReply[Done]`]@java[`StatusReply<Done>`]
|
||||
can be used.
|
||||
|
||||
After validation errors or after persisting events, using a `thenRun` side effect, the reply message can
|
||||
be sent to the `ActorRef`.
|
||||
|
||||
Scala
|
||||
|
|
|
|||
|
|
@ -271,6 +271,9 @@ Scala
|
|||
Java
|
||||
: @@snip [StyleGuideDocExamples.java](/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/StyleGuideDocExamples.java) { #message-protocol }
|
||||
|
||||
Note that the response message hierarchy in this case could be completely avoided by using the @apiDoc[StatusReply] API
|
||||
instead (see @ref[Generic Response Wrapper](interaction-patterns.md#generic-response-wrapper)).
|
||||
|
||||
## Public versus private messages
|
||||
|
||||
Often an actor has some messages that are only for its internal implementation and not part of the public
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue