pekko/akka-docs/src/main/paradox/project/migration-guide-2.4.x-2.5.x.md
2018-09-18 12:56:03 +02:00

764 lines
31 KiB
Markdown

# Migration Guide 2.4.x to 2.5.x
## Actor (Java)
### AbstractActor
`AbstractActor` has been promoted from its experimental/may change state and while doing this we
did some small, but important, improvements to the API that will require some mechanical
changes of your source code.
Previously the receive behavior was set with the `receive` method, but now an actor has
to define its initial receive behavior by implementing the `createReceive` method in
the `AbstractActor`. This has the advantages:
* It gives a clear entry point of what to implement. The compiler tells you that the
abstract method must be implemented.
* It's impossible to forget to set the receive behavior.
* It's not possible to define the receive behavior more than once.
The return type of `createReceive` is `AbstractActor.Receive`. It defines which messages
your Actor can handle, along with the implementation of how the messages should be processed.
You can build such behavior with a builder named `ReceiveBuilder`.
`AbstractActor.Receive` can also be used in `getContext().become`.
The old `receive` method exposed Scala's `PartialFunction` and `BoxedUnit` in the signature,
which are unnecessary concepts for newcomers to learn. The new `createReceive` requires no
additional imports.
Note that The `Receive` can still be implemented in other ways than using the `ReceiveBuilder`
since it in the end is a wrapper around a Scala `PartialFunction`. For example, one could
implement an adapter to [Javaslang Pattern Matching DSL](http://www.javaslang.io/javaslang-docs/#_pattern_matching).
The mechanical source code change for migration to the new `AbstractActor` is to implement the
`createReceive` instead of calling `receive` (compiler will tell that this is missing).
Old:
```
import akka.actor.AbstractActor;
import akka.japi.pf.ReceiveBuilder;
import scala.PartialFunction;
import scala.runtime.BoxedUnit;
public class SomeActor extends AbstractActor {
public SomeActor() {
receive(ReceiveBuilder
.match(String.class, s -> System.out.println(s.toLowerCase())).
.build());
}
}
```
New:
```
import akka.actor.AbstractActor;
public class SomeActor extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.match(String.class, s -> System.out.println(s.toLowerCase()))
.build();
}
}
```
See @ref:[Receive messages](../actors.md#receive-messages) documentation for more advice about how to implement
`createReceive`.
A few new methods have been added with deprecation of the old. Worth noting is `preRestart`.
Old:
```
@Override
public void preRestart(Throwable reason, scala.Option<Object> message) {
super.preRestart(reason, message);
}
```
New:
```
@Override
public void preRestart(Throwable reason, java.util.Optional<Object> message) {
super.preRestart(reason, message);
}
```
### AbstractPersistentActor
Similar change as described above for `AbstractActor` is needed for `AbstractPersistentActor`. Implement `createReceiveRecover`
instead of `receiveRecover`, and `createReceive` instead of `receiveCommand`.
Old:
```
@Override
public PartialFunction<Object, BoxedUnit> receiveCommand() {
return ReceiveBuilder.
match(String.class, cmd -> {/* ... */}).build();
}
@Override
public PartialFunction<Object, BoxedUnit> receiveRecover() {
return ReceiveBuilder.
match(String.class, evt -> {/* ... */}).build();
}
```
New:
```
@Override
public Receive createReceive() {
return receiveBuilder().
match(String.class, cmd -> {/* ... */}).build();
}
@Override
public Receive createReceiveRecover() {
return receiveBuilder().
match(String.class, evt -> {/* ... */}).build();
}
```
### UntypedActor
`UntypedActor` has been deprecated in favor of `AbstractActor`. As a migration path you can extend
`UntypedAbstractActor` instead of `UntypedActor`.
Old:
```
import akka.actor.UntypedActor;
public class SomeActor extends UntypedActor {
public static class Msg1 {}
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof Msg1) {
Msg1 msg1 = (Msg1) msg;
// actual work
} else {
unhandled(msg);
}
}
}
```
New:
```
import akka.actor.UntypedAbstractActor;
public class SomeActor extends UntypedAbstractActor {
public static class Msg1 {}
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof Msg1) {
Msg1 msg1 = (Msg1) msg;
// actual work
} else {
unhandled(msg);
}
}
}
```
It's recommended to migrate `UntypedActor` to `AbstractActor` by implementing
`createReceive` instead of `onReceive`.
Old:
```
import akka.actor.UntypedActor;
public class SomeActor extends UntypedActor {
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof String) {
String s = (String) msg;
System.out.println(s.toLowerCase());
} else {
unhandled(msg);
}
}
}
```
New:
```
import akka.actor.AbstractActor;
public class SomeActor extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.match(String.class, s -> {
System.out.println(s.toLowerCase());
})
.build();
}
}
```
See @ref:[Receive messages](../actors.md#receive-messages) documentation for more advice about how to implement
`createReceive`.
Similar with `UntypedActorWithStash`, `UntypedPersistentActor`, and
`UntypedPersistentActorWithAtLeastOnceDelivery`.
## Actor (Scala)
### Actor DSL deprecation
Actor DSL is a rarely used feature and thus will be deprecated and removed.
Use plain `system.actorOf` instead of the DSL to create Actors if you have been using it.
### ExtensionKey Deprecation
`ExtensionKey` is a shortcut for writing @ref:[Akka Extensions](../extending-akka.md) but extensions created with it
cannot be used from Java and it does in fact not save many lines of code over directly implementing `ExtensionId`.
Old:
```
object MyExtension extends ExtensionKey[MyExtension]
```
New:
```
object MyExtension extends ExtensionId[MyExtension] with ExtensionIdProvider {
override def lookup = MyExtension
override def createExtension(system: ExtendedActorSystem): MyExtension =
new MyExtension(system)
// needed to get the type right when used from Java
override def get(system: ActorSystem): MyExtension = super.get(system)
}
```
## Actor Mailbox
Scala 2.12 is using the standard JDK8 ForkJoinPool, which may cause performance regression for
some Actor messaging scenarios. Therefore we have embedded the ForkJoinPool from Scala 2.11 in
Akka. This breaks binary backwards compatibility for custom `Mailbox` implementations that were
compiled with Akka 2.4.
This is only a problem if you are using a library that provides a custom `Mailbox` implementation.
The change is source compatible and such library should be recompiled and released for Akka 2.5.
## Streams
### Removal of StatefulStage, PushPullStage
`StatefulStage` and `PushPullStage` were first introduced in Akka Streams 1.0, and later deprecated
and replaced by `GraphStage` in 2.0-M2. The `GraphStage` API has all features (and even more) as the
previous APIs and is even nicer to use.
Please refer to the @ref:[GraphStage documentation](../stream/stream-customize.md#graphstage), for details on building custom GraphStages.
`StatefulStage` would be migrated to a simple `GraphStage` that contains some mutable state in its `GraphStageLogic`,
and `PushPullStage` directly translate to graph stages.
### Removal of `Source.transform`, replaced by `via`
Along with the removal of `Stage` (as described above), the `transform` methods creating Flows/Sources/Sinks
from `Stage` have been removed. They are replaced by using `GraphStage` instances with `via`, e.g.:
```
exampleFlow.transform(() => new MyStage())
```
would now be:
```
myFlow.via(new MyGraphStage)
```
as the `GraphStage` itself is a factory of logic instances.
### SubFlow.zip and SubSource.zip now emit akka.japi.Pair instead of Scala's Pair
The the Java API's `zip` operator on `SubFlow` and `SubSource` has been emitting
Scala's `Pair` (`Tuple2`) instead of `akka.japi.Pair`. This is fixed in Akka 2.5 where it emits the proper
Java DSl type.
Please note that the `zip` operator on `Source` and `Flow` has had the correct type,
this change only affects the `Sub...` versions of those classes.
### Deprecation of ActorSubscriber and ActorPublisher
The classes `ActorPublisher` and `ActorSubscriber` were the first user-facing Reactive Streams integration
API that we provided for end-users. Akka Streams APIs have evolved and improved a lot since then, and now
there is no need to use these low-level abstractions anymore. It is easy to get things wrong when implementing them,
and one would have to validate each implementation of such Actor using the Reactive Streams Technology Compatibility Kit.
The replacement API is the powerful `GraphStage`. It has all features that raw Actors provided for implementing Stream
stages and adds additional protocol and type-safety. You can learn all about it in the documentation:
@ref:[Custom stream processing](../stream/stream-customize.md).
You should also read the blog post series on the official team blog, starting with [Mastering GraphStages, part I](http://blog.akka.io/streams/2016/07/30/mastering-graph-stage-part-1),
which explains using and implementing GraphStages in more practical terms than the reference documentation.
### Order of Attributes List
Imporant performance improvement could be achieved by reverting the order of the `attributesList` in `Attributes`.
The `attributeList` is ordered with the most specific attribute first, least specific last.
Note that the order was the opposite in Akka 2.4.x (but it was not really documented).
The semantics of the convenience methods, such as `get` and `getFirst` are the same, but if you use the `attributesList`
directly or via `filtered` or `getAttributeList` you need to take the new order into consideration.
### Dispatcher attribute
The `ActorAttributes.dispatcher` attribute is adding an async boundary in 2.5, since that is the typical desired behavior.
In 2.4 an explicit *async* marker (`AsyncBoundary` attribute) had to be added. For example, this means that `Source` that
defined `blocking-io-dispatcher` as default followed by a `map` will now be separated by an async boundary, which was not
the case in 2.4.
### Removal of the auto-fuse setting
In 2.4 fusing stages together into the same actor could be completely disabled with the setting
`akka.stream.materializer.auto-fusing`. The new materializer introduced in Akka 2.5 does not support disabling fusing,
so this setting does not have any effect any more and has been deprecated. Running each stage in a stream on a separate
actor can be done by adding explicit async boundaries around every stage. How to add asynchronous boundaries can be seen
in @ref:[Operator Fusion](../stream/stream-flows-and-basics.md#operator-fusion).
## Remote
<a id="mig25-mutual"></a>
### Mutual TLS authentication now required by default for netty-based SSL transport
Mutual TLS authentication is now required by default for the netty-based SSL transport.
Nodes that are configured with this setting to `on` might not be able to receive messages from nodes that run on older
versions of akka-remote. This is because in versions of Akka < 2.4.12 the active side of the remoting
connection will not send over certificates even if asked to.
It is still possible to make a rolling upgrade from a version < 2.4.12 by doing the upgrade stepwise:
:
* first, upgrade Akka to the latest version but keep `akka.remote.netty.ssl.require-mutual-authentication` at `off`
and do a first rolling upgrade
* second, turn the setting to `on` and do another rolling upgrade
For more information see the documentation for the `akka.remote.netty.ssl.require-mutual-authentication` configuration setting
in @ref:[akka-remote's reference.conf](../general/configuration.md#config-akka-remote).
<a id="mig25-addser"></a>
### additional-serialization-bindings
From Akka 2.5.0 the `additional-serialization-bindings` are enabled by default. That defines
serializers that are replacing some Java serialization that were used in 2.4. This setting was disabled
by default in Akka 2.4.16 but can also be enabled in an Akka 2.4 system.
To still be able to support rolling upgrade from a system with this setting disabled, e.g. default for 2.4.16,
it is possible to disable the additional serializers and continue using Java serialization for those messages.
```ruby
akka.actor {
# Set this to off to disable serialization-bindings defined in
# additional-serialization-bindings. That should only be needed
# for backwards compatibility reasons.
enable-additional-serialization-bindings = off
}
```
Please note that this setting must be the same on all nodes participating in a cluster, otherwise
the mis-aligned serialization configurations will cause deserialization errors on the receiving nodes.
After performing a rolling upgrade from 2.4 to 2.5 with `enable-additional-serialization-bindings = off`
you can perform another rolling upgrade and change this setting to `on`.
See also @ref:[Rolling upgrades](../serialization.md#rolling-upgrades).
### With serialize-messages the deserialized message is actually sent
The flag `akka.actor.serialize-messages = on` triggers serialization and deserialization of each message sent in the
`ActorSystem`. With this setting enabled the message actually passed on to the actor previously was the original
message instance, this has now changed to be the deserialized message instance.
This may cause tests that rely on messages being the same instance (for example by having mutable messages with attributes
that are asserted in the tests) to not work any more with this setting enabled. For such cases the recommendation is to
either not rely on messages being the same instance or turn the setting off.
### Wire Protocol Compatibility
It is possible to use Akka Remoting between nodes running Akka 2.4.16 and 2.5.x, but some settings have changed so you might need
to adjust some configuration as described in [Rolling Update](#mig25-rolling).
Note however that if using Java serialization it will not be possible to mix nodes using Scala 2.11 and 2.12.
## Cluster
<a id="mig25-rolling"></a>
### Rolling Update
It is possible to do a rolling update from Akka 2.4.16 to 2.5.x, i.e. running a cluster of 2.4.16 nodes and
join nodes running 2.5.x followed by shutting down the old nodes.
You must first update all nodes to 2.4.16. It's not supported to update directly from an older version than
2.4.16 to 2.5.x. For example, if you are running 2.4.11 you must first do a rolling update to 2.4.16, shut down
all 2.4.11 nodes, and then do the rolling update to 2.5.x.
For some configuration settings it's important to use the same values on all nodes in the cluster.
Some settings have changed default value in 2.5.0 and therefore you need to review your configuration
before doing a rolling update to 2.5.x. Such settings are mentioned elsewhere in this migration guide
and here is a summary of things to consider.
* [akka.actor.additional-serialization-bindings](#mig25-addser)
* [akka.cluster.allow-weakly-up-members](#mig25-weaklyup)
* [akka.cluster.sharding.state-store-mode](#mig25-sharding-store)
* [akka.remote.netty.ssl.require-mutual-authentication](#mig25-mutual)
See also the @ref:[rolling update guide](rolling-update.md) for specifics about later patch releases.
#### Limit lookup of routees to nodes tagged with multiple roles
Starting with 2.5.4, cluster routing supports delivering messages to routees tagged with all specified roles
using `use-roles` (instead of `use-role` in previous versions). When doing rolling upgrades and using this new feature,
it is important to first upgrade the existing nodes to the latest version of Akka
and then start using multiple roles in a separate rolling upgrade. Otherwise, if a new node sends a message
with the restriction `use-roles = ["a", "b"]`, that will only require the "a" role on old nodes.
### Coordinated Shutdown
There is a new extension named `CoordinatedShutdown` that will stop certain actors and
services in a specific order and perform registered tasks during the shutdown process.
When using Akka Cluster, tasks for graceful leaving of cluster including graceful
shutdown of Cluster Singletons and Cluster Sharding are now performed automatically.
Previously it was documented that things like terminating the `ActorSystem` should be
done when the cluster member was removed, but this was very difficult to get right.
That is now taken care of automatically. This might result in changed behavior, hopefully
to the better. It might also be in conflict with your previous shutdown code so please
read the documentation for the Coordinated Shutdown and revisit your own implementations.
Most likely your implementation will not be needed any more or it can be simplified.
More information can be found in the @ref:[documentation](../actors.md#coordinated-shutdown).
For some tests it might be undesired to terminate the `ActorSystem` via `CoordinatedShutdown`.
You can disable that by adding the following to the configuration of the `ActorSystem` that is
used in the test:
```
# Don't terminate ActorSystem via CoordinatedShutdown in tests
akka.coordinated-shutdown.terminate-actor-system = off
akka.coordinated-shutdown.run-by-jvm-shutdown-hook = off
akka.cluster.run-coordinated-shutdown-when-down = off
```
<a id="mig25-weaklyup"></a>
### WeaklyUp
@ref:[WeaklyUp](../cluster-usage.md#weakly-up) is now enabled by default, but it can be disabled with configuration option:
```
akka.cluster.allow-weakly-up-members = off
```
You should not run a cluster with this feature enabled on some nodes and disabled on some. Therefore
you might need to enable/disable it in configuration when performing rolling upgrade from 2.4.x to 2.5.0.
<a id="mig25-sharding-store"></a>
### Cluster Sharding state-store-mode
Distributed Data mode, which was still experimental in 2.4.x, is now the default `state-store-mode` for Cluster Sharding. The persistence mode
is also supported. Read more in the @ref:[documentation](../cluster-sharding.md#cluster-sharding-mode).
It's important to use the same mode on all nodes in the cluster, i.e. if you perform a rolling upgrade
from 2.4.16 you might need to change the `state-store-mode` to be the same (`persistence` is default
in 2.4.x):
```
akka.cluster.sharding.state-store-mode = persistence
```
Note that the stored @ref:[Remembering Entities](../cluster-sharding.md#cluster-sharding-remembering) data with `persistence` mode cannot
be migrated to the `data` mode. Such entities must be started again in some other way when using
`ddata` mode.
Rolling upgrades from clusters that already used the (then-experimental) `ddata`
mode are not supported.
### Cluster Sharding remember entities
To use *remember entities* with cluster sharding there are now an additional requirement added: the
`extractShardId` must be able to extract the shard id from the message `Shard.StartEntity(EntityId)`.
This is implies that it must be possible to calculate a shard id from an entity id when using remember
entities.
This was added to be able to gracefully handle when persisted locations of entities does not match
where the entities should live when a shard region starts up. Such states could be cause by changing
the `extractShardId` logic and restart a system using *remember entities*.
### Cluster Management Command Line Tool
There is a new cluster management tool with HTTP API that has the same functionality as the command line tool.
The HTTP API gives you access to cluster membership information as JSON including full reachability status between the nodes.
It supports the ordinary cluster operations such as join, leave, and down.
See documentation of [Akka Management](http://developer.lightbend.com/docs/akka-management/current/).
The command line script for cluster management has been deprecated and is scheduled for removal
in the next major version. Use the HTTP API with [curl](https://curl.haxx.se/) or similar instead.
## Distributed Data
Distributed Data has been promoted to a stable module. This means that we will keep the API stable from this point. As a result
the module name is changed from *akka-distributed-data-experimental* to *akka-distributed-data* and you need to change that in your
build tool (sbt/mvn/...).
### Map allow generic type for the keys
In 2.4 the key of any Distributed Data map always needed to be of type String. In 2.5 you can use any type for the key. This means that
every map (ORMap, LWWMap, PNCounterMap, ORMultiMap) now takes an extra type parameter to specify the key type. To migrate
existing code from 2.4 to 2.5 you simple add String as key type, for example: *ORMultiMap[Foo]* becomes *ORMultiMap[String, Foo]*.
*PNCounterMap* didn't take a type parameter in version 2.4, so *PNCounterMap* in 2.4 becomes *PNCounterMap[String]* in 2.5.
Java developers should use *<>* instead of *[]*, e.g: *PNCounterMap<String>*.
**NOTE: Even though the interface is not compatible between 2.4 and 2.5, the binary protocol over the wire is (as long
as you use String as key type). This means that 2.4 nodes can synchronize with 2.5 nodes.**
### Subscribers
When an entity is removed subscribers will not receive `Replicator.DataDeleted` any more.
They will receive `Replicator.Deleted` instead.
## Persistence
### Binary incompatibility of PersistentActor and AtLeastOneDelivery
To be able to evolve the Java APIs `AbstractPersistentActor` and `AbstractPersistentActorWithAtLeastOnceDelivery`
to work with Scala 2.12 we could find no other solution but to break the binary compatibility of the Scala versions
(which the Java ones were based on).
This means that the Akka 2.5 artifact cannot be a class path drop in replacement of Akka 2.4 if you use
`PersistentActor` or `AtLeastOnceDelivery`, to do this upgrade you _must_ recompile your project with the new
version of Akka.
### Removal of PersistentView
After being deprecated for a long time, and replaced by
@ref:[Persistence Query](../persistence-query.md) `PersistentView` has been removed now removed.
The corresponding query type is `EventsByPersistenceId`. There are several alternatives for connecting the `Source`
to an actor corresponding to a previous `PersistentView`. There are several alternatives for connecting the `Source`
to an actor corresponding to a previous `PersistentView` actor which are documented in @ref:[Integration](../stream/stream-integrations.md).
The consuming actor may be a plain `Actor` or an `PersistentActor` if it needs to store its own state (e.g. `fromSequenceNr` offset).
Please note that Persistence Query is not experimental/may-change anymore in Akka `2.5.0`, so you can safely upgrade to it.
### Persistence Plugin Proxy
A new @ref:[persistence plugin proxy](../persistence.md#persistence-plugin-proxy) was added, that allows sharing of an otherwise
non-sharable journal or snapshot store. The proxy is available by setting `akka.persistence.journal.plugin` or
`akka.persistence.snapshot-store.plugin` to `akka.persistence.journal.proxy` or `akka.persistence.snapshot-store.proxy`,
respectively. The proxy supplants the @ref:[Shared LevelDB journal](../persistence.md#shared-leveldb-journal).
## Persistence Query
Persistence Query has been promoted to a stable module. As a result the module name is changed from *akka-persistence-query-experimental*
to *akka-persistence-query* and you need to change that in your build tool (sbt/mvn/...).
Only slight API changes were made since the module was introduced:
### Query naming consistency improved
Queries always fall into one of the two categories: infinite or finite ("current").
The naming convention for these categories of queries was solidified and is now as follows:
* "infinite" - e.g. `eventsByTag`, `persistenceIds` - which will keep emitting events as they are persisted and match the query.
* "finite", also known as "current" - e.g. `currentEventsByTag`, `currentPersistenceIds` - which will complete the stream once the query completed,
for the journal's definition of "current". For example in an SQL store it would mean it only queries the database once.
Only the `AllPersistenceIdsQuery` class and method name changed due to this.
The class is now called `PersistenceIdsQuery`, and the method which used to be `allPersistenceIds` is now `persistenceIds`.
### Queries now use `Offset` instead of `Long` for offsets
This change was made to better accommodate the various types of Journals and their understanding what an offset is.
For example, in some journals an offset is always a time, while in others it is a numeric offset (like a sequence id).
Instead of the previous `Long` offset you can now use the provided `Offset` factories (and types):
* `akka.persistence.query.Offset.sequence(value: Long)`,
* `akka.persistence.query.Offset.timeBasedUUID(value: UUID)`
* and finally `NoOffset` if not offset should be used.
Journals are also free to provide their own specific `Offset` types. Consult your journal plugin's documentation for details.
## Agents
### Agents are now deprecated
Akka Agents are a very simple way of containing mutable state and allowing to access it safely from
multiple threads. The abstraction is leaky though, as Agents do not work over the network (unlike Akka Actors).
As users were often confused by "when to use an Actor vs. when to use an Agent?" a decision was made to deprecate
the Agents, as they rarely are really enough and do not fit the Akka spirit of thinking about distribution.
We also anticipate to replace the uses of Agents by the upcoming Akka Typed, so in preparation thereof the Agents have been deprecated in 2.5.
If you use Agents and would like to take over the maintenance thereof, please contact the team on Gitter or GitHub.
## Camel
`akka-camel` has been deprecated in favour of [Alpakka](https://github.com/akka/alpakka) ,
the Akka Streams based collection of integrations to various endpoints (including Camel)
We acknowledge that Akka Camel is a very useful and important module. It will not be removed until
Alpakka has reached the needed production quality to be a full replacement. The deprecation of
Akka Camel should be seen as a signal that new development is to be invested in Alpakka instead
of Akka Camel.
## Contrib
`akka-contrib` has been deprecated and is scheduled for removal in the next major version.
The reason is to reduce the amount of things to maintain in the core Akka projects.
Contributions to the core of Akka or its satellite projects are welcome. Contributions
that don't fit into existing modules can be hosted in new Akka GitHub repositories in the
`akka` GitHub organization or outside of it depending on what kind of library it is.
Please ask.
### Aggregator
`Aggregator` has been deprecated. Feel free to copy the source into your project or create a
separate library outside of Akka.
### CircuitBreakerProxy
`CircuitBreakerProxy` has been deprecated in favor of `akka.pattern.CircuitBreaker` with explicit `ask` requests.
### JavaLogger
`akka.contrib.jul.JavaLogger` has been deprecated and included in `akka-actor` instead as
`akka.event.jul.JavaLogger`. See @ref:[documentation](../logging.md#jul).
The `JavaLoggingAdapter` has also been deprecated, but not included in `akka-actor`.
Feel free to copy the source into your project or create a separate library outside of Akka.
### PeekMailbox
`PeekMailbox` has been deprecated. Use an explicit supervisor or proxy actor instead.
<a id="migration-guide-timerbasedthrottler"></a>
### ReceivePipeline
`ReceivePipeline` has been deprecated. Feel free to copy the source into your project or create
a separate library outside of Akka.
### ReliableProxy
`ReliableProxy` has been deprecated. Use @ref:[At-Least-Once Delivery](../persistence.md#at-least-once-delivery) instead. `ReliableProxy`
was only intended as an example and doesn't have full production quality. If there is demand
for a lightweight (non-durable) at-least once delivery mechanism we are open for a design discussion.
### TimerBasedThrottler
`TimerBasedThrottler` has been deprecated. Use the `throttle` stage in Akka Streams instead.
Example in Scala:
```
import scala.concurrent.duration._
import akka.NotUsed
import akka.actor.ActorRef
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.OverflowStrategy
import akka.stream.ThrottleMode
import akka.stream.scaladsl.Sink
import akka.stream.scaladsl.Source
val system: ActorSystem = ??? // TODO real ActorSystem here
val target: ActorRef = ??? // TODO real target ActorRef here
implicit val materializer = ActorMaterializer.create(system)
val throttler: ActorRef =
Source.actorRef(bufferSize = 1000, OverflowStrategy.dropNew)
.throttle(100, 1.second)
.to(Sink.actorRef(target, NotUsed))
.run()
```
Example in Java:
```
import java.util.concurrent.TimeUnit;
import java.time.Duration;
import akka.NotUsed;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import akka.stream.OverflowStrategy;
import akka.stream.ThrottleMode;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
final ActorSystem system = null; // TODO real ActorSystem here
final ActorRef target = null; // TODO real target ActorRef here
final Materializer materializer = ActorMaterializer.create(system);
final ActorRef throttler =
Source.actorRef(1000, OverflowStrategy.dropNew())
.throttle(100, Duration.ofSeconds(1))
.to(Sink.actorRef(target, NotUsed.getInstance()))
.run(materializer);
```
Note, that when using `Sink.actorRef` the sender of the original message sent to the `thottler` ActorRef will be lost and messages will arrive at the `target` with the sender set to `ActorRef.noSender`. Using this construct it is currently impossible to keep the original sender. Alternatively, you can manually specify a static sender by replacing `Sink.actorRef` with @java[`Sink.foreach(msg -> target.tell(msg, whateverSender))`]@scala[`Sink.foreach(msg => target.tell(msg, whateverSender))`]. You could also calculate a sender by inspecting the `msg`. Be cautious not to use `target.tell(msg, sender())` inside of `Sink.foreach` because the result of `sender()` is undefined or will fail when executed from within a stream.
## Akka Typed
With the new term @ref:[may change](../common/may-change.md) we will no longer have a different artifact for modules that are not
stable, and `akka-typed-experimental` has therefore been renamed to `akka-typed`. Note that it is still not
promoted to a stable module.
## Experimental modules
We have previously marked modules that we did not want to freeze the APIs of a **experimental**, such modules will
instead be marked as @ref:[may change](../common/may-change.md) from now on.
## Testkit
`JavaTestKit` has been deprecated since it does all kinds of tricks to achieve what Scala testkit does.
Use `akka.testkit.javadsl.TestKit` instead which introduces nicer APIs.
Old:
```
new JavaTestKit(system) {{
final JavaTestKit probe = new JavaTestKit(system);
new Within(duration("1 second")) {
public void run() {
probe.expectMsgEquals("hello");
}
};
}};
```
New:
```
new TestKit(system) {{
final TestKit probe = new TestKit(system);
within(duration("1 second"), () -> probe.expectMsgEquals("hello"));
}};
```