Deprecate Cluster Client #27242

This commit is contained in:
Patrik Nordwall 2019-09-05 10:24:25 +02:00 committed by Johan Andrén
parent 7e84d242ac
commit cfdce069b4
8 changed files with 142 additions and 6 deletions

View file

@ -5,8 +5,10 @@
package akka.cluster.client
import java.net.URLEncoder
import scala.collection.immutable
import scala.concurrent.duration._
import akka.actor.Actor
import akka.actor.ActorIdentity
import akka.actor.ActorLogging
@ -41,6 +43,9 @@ import akka.util.ccompat._
import scala.collection.immutable.{ HashMap, HashSet }
@ccompatUsedUntil213
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
object ClusterClientSettings {
/**
@ -109,6 +114,9 @@ object ClusterClientSettings {
* to watch it from another actor and possibly acquire a new list of initialContacts from some
* external service registry
*/
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
final class ClusterClientSettings(
val initialContacts: Set[ActorPath],
val establishingGetContactsInterval: FiniteDuration,
@ -271,15 +279,24 @@ final case class ContactPoints(contactPoints: Set[ActorPath]) {
contactPoints.asJava
}
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
object ClusterClient {
/**
* Scala API: Factory method for `ClusterClient` [[akka.actor.Props]].
*/
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
def props(settings: ClusterClientSettings): Props =
Props(new ClusterClient(settings)).withDeploy(Deploy.local)
@SerialVersionUID(1L)
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
final case class Send(path: String, msg: Any, localAffinity: Boolean) {
/**
@ -288,8 +305,15 @@ object ClusterClient {
def this(path: String, msg: Any) = this(path, msg, localAffinity = false)
}
@SerialVersionUID(1L)
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
final case class SendToAll(path: String, msg: Any)
@SerialVersionUID(1L)
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
final case class Publish(topic: String, msg: Any)
/**
@ -344,6 +368,9 @@ object ClusterClient {
* Note that this is a best effort implementation: messages can always be lost due to the distributed
* nature of the actors involved.
*/
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
final class ClusterClient(settings: ClusterClientSettings) extends Actor with ActorLogging {
import ClusterClient._
@ -525,6 +552,9 @@ final class ClusterClient(settings: ClusterClientSettings) extends Actor with Ac
}
}
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
object ClusterClientReceptionist extends ExtensionId[ClusterClientReceptionist] with ExtensionIdProvider {
override def get(system: ActorSystem): ClusterClientReceptionist = super.get(system)
@ -539,6 +569,9 @@ object ClusterClientReceptionist extends ExtensionId[ClusterClientReceptionist]
* with settings defined in config section `akka.cluster.client.receptionist`.
* The [[akka.cluster.pubsub.DistributedPubSubMediator]] is started by the [[akka.cluster.pubsub.DistributedPubSub]] extension.
*/
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
final class ClusterClientReceptionist(system: ExtendedActorSystem) extends Extension {
private val config = system.settings.config.getConfig("akka.cluster.client.receptionist")
@ -614,6 +647,9 @@ final class ClusterClientReceptionist(system: ExtendedActorSystem) extends Exten
receptionist
}
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
object ClusterReceptionistSettings {
/**
@ -663,6 +699,9 @@ object ClusterReceptionistSettings {
* @param responseTunnelReceiveTimeout The actor that tunnel response messages to the
* client will be stopped after this time of inactivity.
*/
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
final class ClusterReceptionistSettings(
val role: Option[String],
val numberOfContacts: Int,
@ -822,6 +861,9 @@ final case class ClusterClients(clusterClients: Set[ActorRef]) {
clusterClients.asJava
}
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
object ClusterReceptionist {
/**
@ -897,6 +939,9 @@ object ClusterReceptionist {
* the client is supposed to communicate directly to the actor in the cluster.
*
*/
@deprecated(
"Use Akka gRPC instead, see https://doc.akka.io/docs/akka/2.6/cluster-client.html#migration-to-akka-grpc",
since = "2.6.0")
final class ClusterReceptionist(pubSubMediator: ActorRef, settings: ClusterReceptionistSettings)
extends Actor
with ActorLogging {

View file

@ -12,9 +12,12 @@ import akka.cluster.client.ClusterReceptionist
import akka.cluster.client.protobuf.msg.{ ClusterClientMessages => cm }
import java.io.NotSerializableException
import com.github.ghik.silencer.silent
/**
* INTERNAL API: Serializer of ClusterClient messages.
*/
@silent("deprecated")
private[akka] class ClusterClientMessageSerializer(val system: ExtendedActorSystem)
extends SerializerWithStringManifest
with BaseSerializer {

View file

@ -10,9 +10,10 @@ import akka.remote.testconductor.RoleName
import akka.remote.testkit.{ MultiNodeConfig, MultiNodeSpec, STMultiNodeSpec }
import akka.testkit.{ ImplicitSender, TestActors }
import com.typesafe.config.ConfigFactory
import scala.concurrent.duration._
import com.github.ghik.silencer.silent
object ClusterClientHandoverSpec extends MultiNodeConfig {
val client = role("client")
val first = role("first")
@ -36,6 +37,7 @@ class ClusterClientHandoverSpecMultiJvmNode1 extends ClusterClientHandoverSpec
class ClusterClientHandoverSpecMultiJvmNode2 extends ClusterClientHandoverSpec
class ClusterClientHandoverSpecMultiJvmNode3 extends ClusterClientHandoverSpec
@silent("deprecated")
class ClusterClientHandoverSpec
extends MultiNodeSpec(ClusterClientHandoverSpec)
with STMultiNodeSpec

View file

@ -6,6 +6,7 @@ package akka.cluster.client
import language.postfixOps
import scala.concurrent.duration._
import com.typesafe.config.ConfigFactory
import akka.actor.{
Actor,
@ -29,9 +30,10 @@ import akka.cluster.pubsub._
import akka.remote.transport.ThrottlerTransportAdapter.Direction
import akka.util.Timeout
import akka.util.unused
import scala.concurrent.Await
import com.github.ghik.silencer.silent
object ClusterClientSpec extends MultiNodeConfig {
val client = role("client")
val first = role("first")
@ -160,6 +162,7 @@ class ClusterClientMultiJvmNode3 extends ClusterClientSpec
class ClusterClientMultiJvmNode4 extends ClusterClientSpec
class ClusterClientMultiJvmNode5 extends ClusterClientSpec
@silent("deprecated")
class ClusterClientSpec extends MultiNodeSpec(ClusterClientSpec) with STMultiNodeSpec with ImplicitSender {
import ClusterClientSpec._

View file

@ -14,6 +14,8 @@ import com.typesafe.config.ConfigFactory
import scala.concurrent.Await
import scala.concurrent.duration._
import com.github.ghik.silencer.silent
object ClusterClientStopSpec extends MultiNodeConfig {
val client = role("client")
val first = role("first")
@ -43,6 +45,7 @@ class ClusterClientStopMultiJvmNode1 extends ClusterClientStopSpec
class ClusterClientStopMultiJvmNode2 extends ClusterClientStopSpec
class ClusterClientStopMultiJvmNode3 extends ClusterClientStopSpec
@silent("deprecated")
class ClusterClientStopSpec extends MultiNodeSpec(ClusterClientStopSpec) with STMultiNodeSpec with ImplicitSender {
import ClusterClientStopSpec._

View file

@ -7,7 +7,9 @@ package akka.cluster.client.protobuf
import akka.actor.ExtendedActorSystem
import akka.testkit.AkkaSpec
import akka.cluster.client.ClusterReceptionist.Internal._
import com.github.ghik.silencer.silent
@silent("deprecated")
class ClusterClientMessageSerializerSpec extends AkkaSpec {
val serializer = new ClusterClientMessageSerializer(system.asInstanceOf[ExtendedActorSystem])

View file

@ -1,7 +1,13 @@
# Classic Cluster Client
@@@ warning
Cluster Client is deprecated in favor of using [Akka gRPC](https://doc.akka.io/docs/akka-grpc/current/index.html).
It is not advised to build new applications with Cluster Client, and existing users @ref[should migrate](#migration-to-akka-grpc).
@@@
@@include[includes.md](includes.md) { #actor-api }
Instead of the cluster client we recommend Akka gRPC (FIXME https://github.com/akka/akka/issues/26175)
## Dependency
@ -219,3 +225,70 @@ This can be useful when initial contacts are provided from some kind of service
are entirely dynamic and the entire cluster might shut down or crash, be restarted on new addresses. Since the
client will be stopped in that case a monitoring actor can watch it and upon `Terminate` a new set of initial
contacts can be fetched and a new cluster client started.
## Migration to Akka gRPC
Cluster Client is deprecated and it is not advised to build new applications with Cluster Client.
We recommend using [Akka gRPC](https://doc.akka.io/docs/akka-grpc/current/index.html) over using Cluster Client.
Cluster Client is convenient to use if you have Akka actors on both client and server side, but
a more decoupled, and therefore better, solution would be to use Akka gRPC and define
application specific protocol buffer messages and gRPC service calls. The benefits are:
* Improved security by using TLS for gRPC (HTTP/2) versus exposing Akka Remoting outside the Akka Cluster
* Easier to update clients and servers independent of each other
* Improved protocol definition between client and server
* Usage of [Akka gRPC Service Discovery](https://doc.akka.io/docs/akka-grpc/current/client/configuration.html#using-akka-discovery-for-endpoint-discovery)
* Clients do not need to use Akka
* See also [gRPC versus Akka Remoting](https://doc.akka.io/docs/akka-grpc/current/whygrpc.html#grpc-vs-akka-remoting)
Existing users of Cluster Client may migrate directly to Akka gRPC, or via a migration
step that requires less re-write of the application. That migration step is described below, but we recommend
new applications use Akka gRPC.
An example is provided to illustrate an approach to migrate from the deprecated Cluster Client to Akka gRPC,
with minimal changes to your existing code. The example is intended to be copied and adjusted to your needs.
It will not be provided as a published artifact.
* [akka-samples/akka-sample-cluster-cluster-client-grpc-scala](https://github.com/akka/akka-samples/tree/2.6/akka-sample-cluster-cluster-client-grpc-scala) implemented in Scala
* [akka-samples/akka-sample-cluster-cluster-client-grpc-java](https://github.com/akka/akka-samples/tree/2.6/akka-sample-cluster-cluster-client-grpc-java) implemented in Java
The example is still using an actor on the client side to have an API that is very close
to the original Cluster Client. The messages this actor can handle correspond to the
@ref:[Distributed Pub Sub](distributed-pub-sub.md) messages on the server side, such as
`ClusterClient.Send` and `ClusterClient.Publish`.
The `ClusterClient` actor delegates those messages to the gRPC client, and on the
server side those are translated and delegated to the destination actors that
are registered via the `ClusterClientReceptionist` in the same way as in the original.
Akka gRPC is used as the transport for the messages between client and server, instead of Akka Remoting.
The application specific messages are wrapped and serialized with Akka Serialization,
which means that care must be taken to keep wire compatibility when changing any messages used
between the client and server. The Akka configuration of Akka serializers must be the same (or
being compatible) on client and server.
### Differences
Aside from the underlying implementation using gRPC instead of Actor messages
and Akka Remoting it's worth pointing out the following differences between
the Cluster Client and the example emulating Cluster Client with Akka gRPC as
transport.
#### Single request-reply
For request-reply interactions when there is only one reply message for each request
it is more efficient to use the `ClusterClient.AskSend` message instead of
`ClusterClient.Send` as illustrated in the example. Then it doesn't have to
setup a full bidirectional gRPC stream for each request but can use the @scala[`Future`]@java[`CompletionStage`]
based API.
#### Initial contact points
Instead of configured initial contact points the [Akka gRPC Service Discovery](https://doc.akka.io/docs/akka-grpc/current/client/configuration.html#using-akka-discovery-for-endpoint-discovery) can be used.
#### Failure detection
Heartbeat messages and failure detection of the connections have been removed
since that should be handled by the gRPC connections.

View file

@ -210,6 +210,11 @@ published, but the transitive dependency to `akka-protobuf` has been removed.
Akka is now using Protobuf version 3.9.0 for serialization of messages defined by Akka.
### Cluster Client
Cluster client has been deprecated as of 2.6 in favor of [Akka gRPC](https://doc.akka.io/docs/akka-grpc/current/index.html).
It is not advised to build new applications with Cluster client, and existing users @ref[should migrate to Akka gRPC](../cluster-client.md#migration-to-akka-grpc).
## Java Serialization
Java serialization is known to be slow and [prone to attacks](https://community.hpe.com/t5/Security-Research/The-perils-of-Java-deserialization/ba-p/6838995)