add ReliableProxy pattern to demo akka-contrib

This commit is contained in:
Roland 2012-09-27 15:57:46 +02:00 committed by Björn Antonsson
parent 26157d0521
commit 0afc3b1721
10 changed files with 731 additions and 54 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -0,0 +1,66 @@
External Contributions
======================
This subproject provides a home to modules contributed by external developers
which may or may not move into the officially supported code base over time.
The conditions under which this transition can occur include:
* there must be enough interest in the module to warrant inclusion in the
standard distribution,
* the module must be actively maintained and
* code quality must be good enough to allow efficient maintenance by the Akka
core development team
If a contributions turns out to not “take off” it may be removed again at a
later time.
Caveat Emptor
-------------
A module in this subproject doesn't have to obey the rule of staying binary
compatible between minor releases. Breaking API changes may be introduced in
minor releases without notice as we refine and simplify based on your feedback.
A module may be dropped in any release without prior deprecation. The Typesafe
subscription does not cover support for these modules.
The Current List of Modules
---------------------------
.. toctree::
reliable-proxy
Suggested Way of Using these Contributions
------------------------------------------
Since the Akka team does not restrict updates to this subproject even during
otherwise binary compatible releases, and modules may be removed without
deprecation, it is suggested to copy the source files into your own code base,
changing the package name. This way you can choose when to update or which
fixes to include (to keep binary compatibility if needed) and later releases of
Akka do not potentially break your application.
Suggested Format of Contributions
---------------------------------
Each contribution should be a self-contained unit, consisting of one source
file or one exclusively used package, without dependencies to other modules in
this subproject; it may depend on everything else in the Akka distribution,
though. This ensures that contributions may be moved into the standard
distribution individually. The module shall be within a subpackage of
``akka.contrib``.
Each module must be accompanied by a test suite which verifies that the
provided features work, possibly complemented by integration and unit tests.
The tests should follow the :ref:`developer_guidelines` and go into the
``src/test/scala`` or ``src/test/java`` directories (with package name matching
the module which is being tested). As an example, if the module were called
``akka.contrib.pattern.ReliableProxy``, then the test suite should be called
``akka.contrib.pattern.ReliableProxySpec``.
Each module must also have proper documentation in `reStructured Text`_ format.
The documentation should be a single ``<module>.rst`` file in the
``akka-contrib/docs`` directory, including a link from ``index.rst`` (this file).
.. _reStructured Text: http://sphinx.pocoo.org/rest.html

View file

@ -0,0 +1,92 @@
Reliable Proxy Pattern
======================
Looking at :ref:`message-send-semantics` one might come to the conclusion that
Akka actors are made for blue-sky scenarios: sending messages is the only way
for actors to communicate, and then that is not even guaranteed to work. Is the
whole paradigm built on sand? Of course the answer is an emphatic “No!”.
A local message send—within the same JVM instance—is not likely to fail, and if
it does the reason was one of
* it was meant to fail (due to consciously choosing a bounded mailbox, which
upon overflow will have to drop messages)
* or it failed due to a catastrophic VM error, e.g. an
:class:`OutOfMemoryError`, a memory access violation (“segmentation fault”,
GPF, etc.), JVM bug—or someone calling ``System.exit()``.
In all of these cases, the actor was very likely not in a position to process
the message anyway, so this part of the non-guarantee is not problematic.
It is a lot more likely for an unintended message delivery failure to occur
when a message send crosses JVM boundaries, i.e. an intermediate unreliable
network is involved. If someone unplugs an ethernet cable, or a power failure
shuts down a router, messages will be lost while the actors would be able to
process them just fine.
.. note::
This does not mean that message send semantics are different between local
and remote operations, it just means that in practice there is a difference
between how good the “best effort” is.
Introducing the Reliable Proxy
------------------------------
.. image:: ReliableProxy.png
To bridge the disparity between “local” and “remote” sends is the goal of this
pattern. When sending from A to B must be as reliable as in-JVM, regardless of
the deployment, then you can interject a reliable tunnel and send through that
instead. The tunnel consists of two end-points, where the ingress point P (the
“proxy”) is a child of A and the egress point E is a child of P, deployed onto
the same network node where B lives. Messages sent to P will be wrapped in an
envelope, tagged with a sequence number and sent to E, who verifies that the
received envelope has the right sequence number (the next expected one) and
forwards the contained message to B. When B receives this message, the
``sender`` will be a reference to the sender of the original message to P.
Reliability is added by E replying to orderly received messages with an ACK, so
that P can tick those messages off its resend list. If ACKs do not come in a
timely fashion, P will try to resend until successful.
Exactly what does it guarantee?
-------------------------------
Sending via a :class:`ReliableProxy` makes the message send exactly as reliable
as if the represented target were to live within the same JVM, provided that
the remote actor system does not terminate. In effect, both ends (i.e. JVM and
actor system) must be considered as one when evaluating the reliability of this
communication channel. The benefit is that the network in-between is taken out
of that equation.
When the target actor terminates, the proxy will terminate as well (on the
terms of :ref:`deathwatch-java` / :ref:`deathwath-scala`).
How to use it
-------------
Since this implementation does not offer much in the way of configuration,
simply instantiate a proxy wrapping some target reference. From Java it looks
like this:
.. includecode:: ../src/test/java/akka/contrib/pattern/ReliableProxyTest.java#imports
.. includecode:: ../src/test/java/akka/contrib/pattern/ReliableProxyTest.java#demo-proxy
And from Scala like this:
.. includecode:: ../src/multi-jvm/scala/akka/contrib/pattern/ReliableProxySpec.scala#demo
Since the :class:`ReliableProxy` actor is an :ref:`fsm-scala`, it also offers
the capability to subscribe to state transitions. If you need to know when all
enqueued messages have been received by the remote end-point (and consequently
been forwarded to the target), you can subscribe to the FSM notifications and
observe a transition from state :class:`ReliableProxy.Active` to state
:class:`ReliableProxy.Idle`.
.. includecode:: ../src/test/java/akka/contrib/pattern/ReliableProxyTest.java#demo-transition
From Scala it would look like so:
.. includecode:: ../src/test/scala/akka/contrib/pattern/ReliableProxyDocSpec.scala#demo-transition