pekko/akka-docs/rst/project/migration-guide-2.1.x-2.2.x.rst
2013-04-29 12:16:27 +02:00

294 lines
16 KiB
ReStructuredText
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

.. _migration-2.2:
################################
Migration Guide 2.1.x to 2.2.x
################################
The 2.2 release contains several structural changes that require some
simple, mechanical source-level changes in client code.
When migrating from 1.3.x to 2.1.x you should first follow the instructions for
migrating :ref:`1.3.x to 2.0.x <migration-2.0>` and then :ref:`2.0.x to 2.1.x <migration-2.1>`.
Deprecated Closure-Taking Props
===============================
:class:`Props` instances used to contain a closure which produces an
:class:`Actor` instance when invoked. This approach is flawed in that closures
are usually created in-line and thus carry a reference to their enclosing
object; this is not well known among programmers, in particular it can be
surprising that innocent-looking actor creation should not be serializable,
e.g. if the enclosing class is an actor.
Thus we have decided to deprecate ``Props(new MyActor(...))`` and
:class:`UntypedActorFactory` in favor of basing :class:`Props` on a
:class:`Class` and a sequence of constructor arguments. This has the added
benefit of allowing easier integration with dependency injection frameworks,
see :ref:`actor-create-factory`.
The deprecated methods will be retained until the possibility of reintroducing
a similar syntax in a safe fashion has been properly researched (in case of
Scala it might be possible to use macros to this effect).
Immutable everywhere
====================
Akka has in 2.2 been refactored to require ``scala.collection.immutable`` data structures as much as possible,
this leads to fewer bugs and more opportunity for sharing data safely.
==================================== ====================================
Search Replace with
==================================== ====================================
``akka.japi.Util.arrayToSeq`` ``akka.japi.Util.immutableSeq``
==================================== ====================================
If you need to convert from Java to ``scala.collection.immutable.Seq`` or ``scala.collection.immutable.Iterable`` you should use ``akka.japi.Util.immutableSeq(…)``,
and if you need to convert from Scala you can simply switch to using immutable collections yourself or use the ``to[immutable.<collection-type>]`` method.
ActorContext & ActorRefFactory dispatcher
=========================================
The return type of ``ActorContext``'s and ``ActorRefFactory``'s ``dispatcher``-method now returns ``ExecutionContext`` instead of ``MessageDispatcher``.
API changes to FSM and TestFSMRef
=================================
The ``timerActive_?`` method has been deprecated in both the ``FSM`` trait and the ``TestFSMRef``
class. You should now use the ``isTimerActive`` method instead. The old method will remain
throughout 2.2.x. It will be removed in Akka 2.3.
ThreadPoolConfigBuilder
=======================
``akka.dispatch.ThreadPoolConfigBuilder`` companion object has been removed,
and with it the ``conf_?`` method that was essentially only a type-inferencer aid for creation
of optional transformations on ``ThreadPoolConfigBuilder``.
Instead use: ``option.map(o => (t: ThreadPoolConfigBuilder) => t.op(o))``.
Scheduler
=========
Akka's ``Scheduler`` has been augmented to also include a ``sender`` when scheduling to send messages, this should work Out-Of-The-Box for Scala users,
but for Java Users you will need to manually provide the ``sender`` as usual use ``null`` to designate "no sender" which will behave just as before the change.
ZeroMQ ByteString
=================
``akka.zeromq.Frame`` and the use of ``Seq[Byte]`` in the API has been removed and is replaced by ``akka.util.ByteString``.
``ZMQMessage.firstFrameAsString`` has been removed, please use ``ZMQMessage.frames`` or ``ZMQMessage.frame(int)`` to access the frames.
Brand new Agents
================
Akka's ``Agent`` has been rewritten to improve the API and to remove the need to manually ``close`` an Agent.
It's also now an abstract class with the potential for subtyping and has a new factory method
allowing Java to correctly infer the type of the Agent.
The Java API has also been harmonized so both Java and Scala call the same methods.
======================================================= =======================================================
Old Java API New Java API
======================================================= =======================================================
``new Agent<type>(value, actorSystem)`` ``Agent.create(value, executionContext)``
``agent.update(newValue)`` ``agent.send(newValue)``
``agent.future(Timeout)`` ``agent.future()``
``agent.await(Timeout)`` ``Await.result(agent.future(), Timeout)``
``agent.send(Function)`` ``agent.send(Mapper)``
``agent.sendOff(Function, ExecutionContext)`` ``agent.sendOff(Mapper, ExecutionContext)``
``agent.alter(Function, Timeout)`` ``agent.alter(Mapper)``
``agent.alterOff(Function, Timeout, ExecutionContext)`` ``agent.alter(Mapper, ExecutionContext)``
``agent.map(Function)`` ``agent.map(Mapper)``
``agent.flatMap(Function)`` ``agent.flatMap(Mapper)``
``agent.foreach(Procedure)`` ``agent.foreach(Foreach)``
``agent.suspend()`` ``No replacement, pointless feature``
``agent.resume()`` ``No replacement, pointless feature``
``agent.close()`` ``No replacement, not needed in new implementation``
======================================================= =======================================================
======================================================== ========================================================
Old Scala API New Scala API
======================================================== ========================================================
``Agent[T](value)(implicit ActorSystem)`` ``Agent[T](value)(implicit ExecutionContext)``
``agent.update(newValue)`` ``agent.send(newValue)``
``agent.alterOff(Function1)(Timeout, ExecutionContext)`` ``agent.alterOff(Function1)(ExecutionContext)``
``agent.await(Timeout)`` ``Await.result(agent.future, Timeout)``
``agent.future(Timeout)`` ``agent.future``
``agent.suspend()`` ``No replacement, pointless feature``
``agent.resume()`` ``No replacement, pointless feature``
``agent.close()`` ``No replacement, not needed in new implementation``
======================================================== ========================================================
``event-handlers`` renamed to ``loggers``
=========================================
If you have defined custom event handlers (loggers) in your configuration you need to change
``akka.event-handlers`` to ``akka.loggers`` and
``akka.event-handler-startup-timeout`` to ``akka.logger-startup-timeout``.
The SLF4J logger has been renamed from ``akka.event.slf4j.Slf4jEventHandler`` to
``akka.event.slf4j.Slf4jLogger``.
The ``java.util.logging`` logger has been renamed from ``akka.contrib.jul.JavaLoggingEventHandler`` to
``akka.contrib.jul.JavaLogger``.
Remoting
========
The remoting subsystem of Akka has been replaced in favor of a more flexible, pluggable driver based implementation. This
has required some changes to the configuration sections of ``akka.remote``, the format of Akka remote addresses
and the Akka protocol itself.
The internal communication protocol of Akka has been evolved into a completely standalone entity, not tied to any
particular transport. This change has the effect that Akka 2.2 remoting is no longer able to directly communicate with
older versions.
The ``akka.remote.transport`` configuration key has been removed as the remoting system itself is no longer replaceable.
Custom transports are now pluggable via the ``akka.remote.enabled-transpotrs`` key (see the :meth:`akka.remote.Transport` SPI
and the documentation of remoting for more detail on drivers). The transport loaded by default is a Netty based TCP
driver similar in functionality to the default remoting in Akka 2.1.
Transports are now fully pluggable through drivers, therefore transport specific settings like listening ports now live in the namespace
of their driver configuration. In particular TCP related settings are now under ``akka.remote.netty.tcp``.
As a result of being able to replace the transport protocol, it is now necessary to include the protocol information
in Akka URLs for remote addresses. Therefore a remote address of ``akka://remote-sys@remotehost:2552/user/actor``
has to be changed to ``akka.tcp://remote-sys@remotehost:2552/user/actor`` if the remote system uses TCP as transport. If
the other system uses SSL on top of TCP, the correct address would be ``akka.ssl.tcp://remote-sys@remotehost:2552/user/actor``.
Remote lifecycle events have been changed to a more coarse-grained, simplified model. All remoting events are subclasses
of :meth:`akka.remote.RemotingLifecycle`. Events related to the lifecycle of *associations* (formerly called *connections*)
be it inbound or outbound are subclasses of :meth:`akka.remote.AssociationEvent` (which is in turn a subclass of
:meth:`RemotingLifecycle`). The direction of the association (inbound or outbound) triggering an ``AssociationEvent`` is
available via the ``inbound`` boolean field of the event.
.. note::
The change in terminology from "Connection" to "Association" reflects the fact that the remoting subsystem may use
connectionless transports, but an association similar to transport layer connections is maintained between endpoints
by the Akka protocol.
New configuration settings are also available, see the remoting documentation for more detail: :ref:`remoting-scala`
.. _migration_2.2_actorSelection:
Use ``actorSelection`` instead of ``actorFor``
==============================================
``actorFor`` is deprecated in favor of ``actorSelection`` because actor references
acquired with ``actorFor`` behave differently for local and remote actors.
In the case of a local actor reference, the named actor needs to exist before the
lookup, or else the acquired reference will be an :class:`EmptyLocalActorRef`.
This will be true even if an actor with that exact path is created after acquiring
the actor reference. For remote actor references acquired with `actorFor` the
behaviour is different and sending messages to such a reference will under the hood
look up the actor by path on the remote system for every message send.
Messages can be sent via the :class:`ActorSelection` and the path of the
:class:`ActorSelection` is looked up when delivering each message. If the selection
does not match any actors the message will be dropped.
To acquire an :class:`ActorRef` for an :class:`ActorSelection` you need to
send a message to the selection and use the ``sender`` reference of the reply from
the actor. There is a built-in ``Identify`` message that all Actors will understand
and automatically reply to with a ``ActorIdentity`` message containing the
:class:`ActorRef`.
Read more about ``actorSelection`` in :ref:`docs for Java <actorSelection-java>` or
:ref:`docs for Scala <actorSelection-scala>`.
ActorRef equality and sending to remote actors
==============================================
Sending messages to an ``ActorRef`` must have the same semantics no matter if the target actor is located
on a remote host or in the same ``ActorSystem`` in the same JVM. This was not always the case. For example
when the target actor is terminated and created again under the same path. Sending to local references
of the previous incarnation of the actor will not be delivered to the new incarnation, but that was the case
for remote references. The reason was that the target actor was looked up by its path on every message
delivery and the path didn't distinguish between the two incarnations of the actor. This has been fixed, and
messages sent to a remote reference that points to a terminated actor will not be delivered to a new
actor with the same path.
Equality of ``ActorRef`` has been changed to match the intention that an ``ActorRef`` corresponds to the target
actor instance. Two actor references are compared equal when they have the same path and point to the same
actor incarnation. A reference pointing to a terminated actor does not compare equal to a reference pointing
to another (re-created) actor with the same path. Note that a restart of an actor caused by a failure still
means that it's the same actor incarnation, i.e. a restart is not visible for the consumer of the ``ActorRef``.
Equality in 2.1 was only based on the path of the ``ActorRef``. If you need to keep track of actor references
in a collection and do not care about the exact actor incarnation you can use the ``ActorPath`` as key, because
the identifier of the target actor is not taken into account when comparing actor paths.
Remote actor references acquired with ``actorFor`` do not include the full information about the underlying actor
identity and therefore such references do not compare equal to references acquired with ``actorOf``,
``sender``, or ``context.self``. Because of this ``actorFor`` is deprecated, as explained in
:ref:`migration_2.2_actorSelection`.
Note that when a parent actor is restarted its children are by default stopped and re-created, i.e. the child
after the restart will be a different incarnation than the child before the restart. This has always been the
case, but in some situations you might not have noticed, e.g. when comparing such actor references or sending
messages to remote deployed children of a restarted parent.
This may also have implications if you compare the ``ActorRef`` received in a ``Terminated`` message
with an expected ``ActorRef``.
The following will not match::
val ref = context.actorFor("akka.tcp://actorSystemName@10.0.0.1:2552/user/actorName")
def receive = {
case Terminated(`ref`) => // ...
}
Instead, use actorSelection followed by identify request, and watch the verified actor reference::
val selection = context.actorSelection("akka.tcp://actorSystemName@10.0.0.1:2552/user/actorName")
selection ! Identify(None)
var ref: ActorRef = _
def receive = {
case ActorIdentity(_, Some(actorRef)) =>
ref = actorRef
context watch ref
case ActorIdentity(_, None) => // not alive
case Terminated(`ref`) => // ...
}
Use ``watch`` instead of ``isTerminated``
=========================================
``ActorRef.isTerminated`` is deprecated in favor of ``ActorContext.watch`` because
``isTerminated`` behaves differently for local and remote actors.
DeathWatch Semantics are Simplified
===================================
DeathPactException is now Fatal
-------------------------------
Previously an unhandled :class:`Terminated` message which led to a
:class:`DeathPactException` to the thrown would be answered with a ``Restart``
directive by the default supervisor strategy. This is not intuitive given the
name of the exception and the Erlang linking feature by which it was inspired.
The default strategy has thus be changed to return ``Stop`` in this case.
It can be argued that previously the actor would likely run into a restart loop
because watching a terminated actor would lead to a :class:`DeathPactException`
immediately again.
Unwatching now Prevents Reception of Terminated
-----------------------------------------------
Previously calling :meth:`ActorContext.unwatch` would unregister lifecycle
monitoring interest, but if the target actor had terminated already the
:class:`Terminated` message had already been enqueued and would be received
later—possibly leading to a :class:`DeathPactException`. This behavior has been
modified such that the :class:`Terminated` message will be silently discarded
if :meth:`unwatch` is called before processing the :class:`Terminated`
message. Therefore the following is now safe::
context.stop(target)
context.unwatch(target)