Merge paradox/scala/event-bus.md and java/event-bus.md (#23155)
This commit is contained in:
parent
f90133499a
commit
17e07c0ae2
2 changed files with 100 additions and 226 deletions
|
|
@ -1,204 +0,0 @@
|
|||
# Event Bus
|
||||
|
||||
Originally conceived as a way to send messages to groups of actors, the
|
||||
`EventBus` has been generalized into a set of abstract base classes
|
||||
implementing a simple interface:
|
||||
|
||||
@@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #event-bus-api }
|
||||
|
||||
@@@ note
|
||||
|
||||
Please note that the EventBus does not preserve the sender of the
|
||||
published messages. If you need a reference to the original sender
|
||||
you have to provide it inside the message.
|
||||
|
||||
@@@
|
||||
|
||||
This mechanism is used in different places within Akka, e.g. the [Event Stream](#event-stream).
|
||||
Implementations can make use of the specific building blocks presented below.
|
||||
|
||||
An event bus must define the following three type parameters:
|
||||
|
||||
* `Event` (E) is the type of all events published on that bus
|
||||
* `Subscriber` (S) is the type of subscribers allowed to register on that
|
||||
event bus
|
||||
* `Classifier` (C) defines the classifier to be used in selecting
|
||||
subscribers for dispatching events
|
||||
|
||||
The traits below are still generic in these types, but they need to be defined
|
||||
for any concrete implementation.
|
||||
|
||||
## Classifiers
|
||||
|
||||
The classifiers presented here are part of the Akka distribution, but rolling
|
||||
your own in case you do not find a perfect match is not difficult, check the
|
||||
implementation of the existing ones on @extref[github](github:akka-actor/src/main/scala/akka/event/EventBus.scala)
|
||||
|
||||
### Lookup Classification
|
||||
|
||||
The simplest classification is just to extract an arbitrary classifier from
|
||||
each event and maintaining a set of subscribers for each possible classifier.
|
||||
This can be compared to tuning in on a radio station. The trait
|
||||
`LookupClassification` is still generic in that it abstracts over how to
|
||||
compare subscribers and how exactly to classify.
|
||||
|
||||
The necessary methods to be implemented are illustrated with the following example:
|
||||
|
||||
@@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #lookup-bus }
|
||||
|
||||
A test for this implementation may look like this:
|
||||
|
||||
@@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #lookup-bus-test }
|
||||
|
||||
This classifier is efficient in case no subscribers exist for a particular event.
|
||||
|
||||
### Subchannel Classification
|
||||
|
||||
If classifiers form a hierarchy and it is desired that subscription be possible
|
||||
not only at the leaf nodes, this classification may be just the right one. It
|
||||
can be compared to tuning in on (possibly multiple) radio channels by genre.
|
||||
This classification has been developed for the case where the classifier is
|
||||
just the JVM class of the event and subscribers may be interested in
|
||||
subscribing to all subclasses of a certain class, but it may be used with any
|
||||
classifier hierarchy.
|
||||
|
||||
The necessary methods to be implemented are illustrated with the following example:
|
||||
|
||||
@@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #subchannel-bus }
|
||||
|
||||
A test for this implementation may look like this:
|
||||
|
||||
@@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #subchannel-bus-test }
|
||||
|
||||
This classifier is also efficient in case no subscribers are found for an
|
||||
event, but it uses conventional locking to synchronize an internal classifier
|
||||
cache, hence it is not well-suited to use cases in which subscriptions change
|
||||
with very high frequency (keep in mind that “opening” a classifier by sending
|
||||
the first message will also have to re-check all previous subscriptions).
|
||||
|
||||
### Scanning Classification
|
||||
|
||||
The previous classifier was built for multi-classifier subscriptions which are
|
||||
strictly hierarchical, this classifier is useful if there are overlapping
|
||||
classifiers which cover various parts of the event space without forming a
|
||||
hierarchy. It can be compared to tuning in on (possibly multiple) radio
|
||||
stations by geographical reachability (for old-school radio-wave transmission).
|
||||
|
||||
The necessary methods to be implemented are illustrated with the following example:
|
||||
|
||||
@@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #scanning-bus }
|
||||
|
||||
A test for this implementation may look like this:
|
||||
|
||||
@@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #scanning-bus-test }
|
||||
|
||||
This classifier takes always a time which is proportional to the number of
|
||||
subscriptions, independent of how many actually match.
|
||||
|
||||
<a id="actor-classification"></a>
|
||||
### Actor Classification
|
||||
|
||||
This classification was originally developed specifically for implementing
|
||||
@ref:[DeathWatch](actors.md#deathwatch): subscribers as well as classifiers are of
|
||||
type `ActorRef`.
|
||||
|
||||
This classification requires an `ActorSystem` in order to perform book-keeping
|
||||
operations related to the subscribers being Actors, which can terminate without first
|
||||
unsubscribing from the EventBus. ManagedActorClassification maintains a system Actor which
|
||||
takes care of unsubscribing terminated actors automatically.
|
||||
|
||||
The necessary methods to be implemented are illustrated with the following example:
|
||||
|
||||
@@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #actor-bus }
|
||||
|
||||
A test for this implementation may look like this:
|
||||
|
||||
@@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #actor-bus-test }
|
||||
|
||||
This classifier is still is generic in the event type, and it is efficient for
|
||||
all use cases.
|
||||
|
||||
<a id="event-stream"></a>
|
||||
## Event Stream
|
||||
|
||||
The event stream is the main event bus of each actor system: it is used for
|
||||
carrying @ref:[log messages](logging.md) and [Dead Letters](#dead-letters) and may be
|
||||
used by the user code for other purposes as well. It uses [Subchannel
|
||||
Classification](#subchannel-classification) which enables registering to related sets of channels (as is
|
||||
used for `RemotingLifecycleEvent`). The following example demonstrates
|
||||
how a simple subscription works. Given a simple actor:
|
||||
|
||||
@@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #imports-deadletter }
|
||||
|
||||
@@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #deadletter-actor }
|
||||
|
||||
it can be subscribed like this:
|
||||
|
||||
@@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #deadletters }
|
||||
|
||||
It is also worth pointing out that thanks to the way the subchannel classification
|
||||
is implemented in the event stream, it is possible to subscribe to a group of events, by
|
||||
subscribing to their common superclass as demonstrated in the following example:
|
||||
|
||||
@@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #superclass-subscription-eventstream }
|
||||
|
||||
Similarly to [Actor Classification](#actor-classification), `EventStream` will automatically remove subscribers when they terminate.
|
||||
|
||||
@@@ note
|
||||
|
||||
The event stream is a *local facility*, meaning that it will *not* distribute events to other nodes in a clustered environment (unless you subscribe a Remote Actor to the stream explicitly).
|
||||
If you need to broadcast events in an Akka cluster, *without* knowing your recipients explicitly (i.e. obtaining their ActorRefs), you may want to look into: @ref:[Distributed Publish Subscribe in Cluster](distributed-pub-sub.md).
|
||||
|
||||
@@@
|
||||
|
||||
### Default Handlers
|
||||
|
||||
Upon start-up the actor system creates and subscribes actors to the event
|
||||
stream for logging: these are the handlers which are configured for example in
|
||||
`application.conf`:
|
||||
|
||||
```text
|
||||
akka {
|
||||
loggers = ["akka.event.Logging$DefaultLogger"]
|
||||
}
|
||||
```
|
||||
|
||||
The handlers listed here by fully-qualified class name will be subscribed to
|
||||
all log event classes with priority higher than or equal to the configured
|
||||
log-level and their subscriptions are kept in sync when changing the log-level
|
||||
at runtime:
|
||||
|
||||
```
|
||||
system.eventStream.setLogLevel(Logging.DebugLevel());
|
||||
```
|
||||
|
||||
This means that log events for a level which will not be logged are
|
||||
typically not dispatched at all (unless manual subscriptions to the respective
|
||||
event class have been done)
|
||||
|
||||
### Dead Letters
|
||||
|
||||
As described at @ref:[Stopping actors](actors.md#stopping-actors), messages queued when an actor
|
||||
terminates or sent after its death are re-routed to the dead letter mailbox,
|
||||
which by default will publish the messages wrapped in `DeadLetter`. This
|
||||
wrapper holds the original sender, receiver and message of the envelope which
|
||||
was redirected.
|
||||
|
||||
Some internal messages (marked with the `DeadLetterSuppression` trait) will not end up as
|
||||
dead letters like normal messages. These are by design safe and expected to sometimes arrive at a terminated actor
|
||||
and since they are nothing to worry about, they are suppressed from the default dead letters logging mechanism.
|
||||
|
||||
However, in case you find yourself in need of debugging these kinds of low level suppressed dead letters,
|
||||
it's still possible to subscribe to them explicitly:
|
||||
|
||||
@@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #suppressed-deadletters }
|
||||
|
||||
or all dead letters (including the suppressed ones):
|
||||
|
||||
@@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #all-deadletters }
|
||||
|
||||
### Other Uses
|
||||
|
||||
The event stream is always there and ready to be used, just publish your own
|
||||
events (it accepts `Object`) and subscribe listeners to the corresponding JVM
|
||||
classes.
|
||||
1
akka-docs/src/main/paradox/java/event-bus.md
Symbolic link
1
akka-docs/src/main/paradox/java/event-bus.md
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../scala/event-bus.md
|
||||
|
|
@ -1,10 +1,15 @@
|
|||
# Event Bus
|
||||
|
||||
Originally conceived as a way to send messages to groups of actors, the
|
||||
`EventBus` has been generalized into a set of composable traits
|
||||
`EventBus` has been generalized into a set of abstract base classes
|
||||
`EventBus` has been generalized into a set of @scala[composable traits] @java[abstract base classes]
|
||||
implementing a simple interface:
|
||||
|
||||
@@snip [EventBus.scala]($akka$/akka-actor/src/main/scala/akka/event/EventBus.scala) { #event-bus-api }
|
||||
Scala
|
||||
: @@snip [EventBus.scala]($akka$/akka-actor/src/main/scala/akka/event/EventBus.scala) { #event-bus-api }
|
||||
|
||||
Java
|
||||
: @@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #event-bus-api }
|
||||
|
||||
@@@ note
|
||||
|
||||
|
|
@ -17,11 +22,11 @@ you have to provide it inside the message.
|
|||
This mechanism is used in different places within Akka, e.g. the [Event Stream](#event-stream).
|
||||
Implementations can make use of the specific building blocks presented below.
|
||||
|
||||
An event bus must define the following three abstract types:
|
||||
An event bus must define the following three type parameters:
|
||||
An event bus must define the following three @scala[abstract types]@java[type parameters]:
|
||||
|
||||
* `Event` is the type of all events published on that bus
|
||||
* `Subscriber` is the type of subscribers allowed to register on that
|
||||
event bus
|
||||
* `Subscriber` is the type of subscribers allowed to register on that event bus
|
||||
* `Classifier` defines the classifier to be used in selecting
|
||||
subscribers for dispatching events
|
||||
|
||||
|
|
@ -44,11 +49,19 @@ compare subscribers and how exactly to classify.
|
|||
|
||||
The necessary methods to be implemented are illustrated with the following example:
|
||||
|
||||
@@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #lookup-bus }
|
||||
Scala
|
||||
: @@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #lookup-bus }
|
||||
|
||||
Java
|
||||
: @@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #lookup-bus }
|
||||
|
||||
A test for this implementation may look like this:
|
||||
|
||||
@@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #lookup-bus-test }
|
||||
Scala
|
||||
: @@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #lookup-bus-test }
|
||||
|
||||
Java
|
||||
: @@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #lookup-bus-test }
|
||||
|
||||
This classifier is efficient in case no subscribers exist for a particular event.
|
||||
|
||||
|
|
@ -64,11 +77,19 @@ classifier hierarchy.
|
|||
|
||||
The necessary methods to be implemented are illustrated with the following example:
|
||||
|
||||
@@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #subchannel-bus }
|
||||
Scala
|
||||
: @@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #subchannel-bus }
|
||||
|
||||
Java
|
||||
: @@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #subchannel-bus }
|
||||
|
||||
A test for this implementation may look like this:
|
||||
|
||||
@@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #subchannel-bus-test }
|
||||
Scala
|
||||
: @@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #subchannel-bus-test }
|
||||
|
||||
Java
|
||||
: @@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #subchannel-bus-test }
|
||||
|
||||
This classifier is also efficient in case no subscribers are found for an
|
||||
event, but it uses conventional locking to synchronize an internal classifier
|
||||
|
|
@ -86,11 +107,19 @@ stations by geographical reachability (for old-school radio-wave transmission).
|
|||
|
||||
The necessary methods to be implemented are illustrated with the following example:
|
||||
|
||||
@@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #scanning-bus }
|
||||
Scala
|
||||
: @@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #scanning-bus }
|
||||
|
||||
Java
|
||||
: @@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #scanning-bus }
|
||||
|
||||
A test for this implementation may look like this:
|
||||
|
||||
@@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #scanning-bus-test }
|
||||
Scala
|
||||
: @@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #scanning-bus-test }
|
||||
|
||||
Java
|
||||
: @@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #scanning-bus-test }
|
||||
|
||||
This classifier takes always a time which is proportional to the number of
|
||||
subscriptions, independent of how many actually match.
|
||||
|
|
@ -109,11 +138,19 @@ takes care of unsubscribing terminated actors automatically.
|
|||
|
||||
The necessary methods to be implemented are illustrated with the following example:
|
||||
|
||||
@@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #actor-bus }
|
||||
Scala
|
||||
: @@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #actor-bus }
|
||||
|
||||
Java
|
||||
: @@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #actor-bus }
|
||||
|
||||
A test for this implementation may look like this:
|
||||
|
||||
@@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #actor-bus-test }
|
||||
Scala
|
||||
: @@snip [EventBusDocSpec.scala]($code$/scala/docs/event/EventBusDocSpec.scala) { #actor-bus-test }
|
||||
|
||||
Java
|
||||
: @@snip [EventBusDocTest.java]($code$/java/jdocs/event/EventBusDocTest.java) { #actor-bus-test }
|
||||
|
||||
This classifier is still is generic in the event type, and it is efficient for
|
||||
all use cases.
|
||||
|
|
@ -126,15 +163,37 @@ carrying @ref:[log messages](logging.md) and [Dead Letters](#dead-letters) and m
|
|||
used by the user code for other purposes as well. It uses [Subchannel
|
||||
Classification](#subchannel-classification) which enables registering to related sets of channels (as is
|
||||
used for `RemotingLifecycleEvent`). The following example demonstrates
|
||||
how a simple subscription works:
|
||||
how a simple subscription works. Given a simple actor:
|
||||
|
||||
@@@ div { .group-scala }
|
||||
|
||||
@@snip [LoggingDocSpec.scala]($code$/scala/docs/event/LoggingDocSpec.scala) { #deadletters }
|
||||
|
||||
@@@
|
||||
|
||||
@@@ div { .group-java }
|
||||
|
||||
@@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #imports-deadletter }
|
||||
|
||||
@@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #deadletter-actor }
|
||||
|
||||
it can be subscribed like this:
|
||||
It can be subscribed like this:
|
||||
|
||||
@@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #deadletters }
|
||||
|
||||
@@@
|
||||
|
||||
|
||||
It is also worth pointing out that thanks to the way the subchannel classification
|
||||
is implemented in the event stream, it is possible to subscribe to a group of events, by
|
||||
subscribing to their common superclass as demonstrated in the following example:
|
||||
|
||||
@@snip [LoggingDocSpec.scala]($code$/scala/docs/event/LoggingDocSpec.scala) { #superclass-subscription-eventstream }
|
||||
Scala
|
||||
: @@snip [LoggingDocSpec.scala]($code$/scala/docs/event/LoggingDocSpec.scala) { #superclass-subscription-eventstream }
|
||||
|
||||
Java
|
||||
: @@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #superclass-subscription-eventstream }
|
||||
|
||||
Similarly to [Actor Classification](#actor-classification), `EventStream` will automatically remove subscribers when they terminate.
|
||||
|
||||
|
|
@ -162,11 +221,21 @@ all log event classes with priority higher than or equal to the configured
|
|||
log-level and their subscriptions are kept in sync when changing the log-level
|
||||
at runtime:
|
||||
|
||||
```
|
||||
system.eventStream.setLogLevel(Logging.DebugLevel)
|
||||
```
|
||||
Scala
|
||||
: @@@vars
|
||||
```
|
||||
system.eventStream.setLogLevel(Logging.DebugLevel)
|
||||
```
|
||||
@@@
|
||||
|
||||
This means that log events for a level which will not be logged are not
|
||||
Java
|
||||
: @@@vars
|
||||
```
|
||||
system.eventStream.setLogLevel(Logging.DebugLevel());
|
||||
```
|
||||
@@@
|
||||
|
||||
This means that log events for a level which will not be logged are
|
||||
typically not dispatched at all (unless manual subscriptions to the respective
|
||||
event class have been done)
|
||||
|
||||
|
|
@ -185,14 +254,22 @@ and since they are nothing to worry about, they are suppressed from the default
|
|||
However, in case you find yourself in need of debugging these kinds of low level suppressed dead letters,
|
||||
it's still possible to subscribe to them explicitly:
|
||||
|
||||
@@snip [LoggingDocSpec.scala]($code$/scala/docs/event/LoggingDocSpec.scala) { #suppressed-deadletters }
|
||||
Scala
|
||||
: @@snip [LoggingDocSpec.scala]($code$/scala/docs/event/LoggingDocSpec.scala) { #suppressed-deadletters }
|
||||
|
||||
Java
|
||||
: @@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #suppressed-deadletters }
|
||||
|
||||
or all dead letters (including the suppressed ones):
|
||||
|
||||
@@snip [LoggingDocSpec.scala]($code$/scala/docs/event/LoggingDocSpec.scala) { #all-deadletters }
|
||||
Scala
|
||||
: @@snip [LoggingDocSpec.scala]($code$/scala/docs/event/LoggingDocSpec.scala) { #all-deadletters }
|
||||
|
||||
Java
|
||||
: @@snip [LoggingDocTest.java]($code$/java/jdocs/event/LoggingDocTest.java) { #all-deadletters }
|
||||
|
||||
### Other Uses
|
||||
|
||||
The event stream is always there and ready to be used, just publish your own
|
||||
events (it accepts `AnyRef`) and subscribe listeners to the corresponding JVM
|
||||
events (it accepts @scala[`AnyRef`]@java[`Object`]) and subscribe listeners to the corresponding JVM
|
||||
classes.
|
||||
Loading…
Add table
Add a link
Reference in a new issue