!clt #13523 Don't expose sender in cluster client replies
This commit is contained in:
parent
e19d3cb3e8
commit
7533df48cf
5 changed files with 41 additions and 25 deletions
|
|
@ -524,7 +524,7 @@ object ClusterReceptionist {
|
||||||
def receive = {
|
def receive = {
|
||||||
case Ping ⇒ // keep alive from client
|
case Ping ⇒ // keep alive from client
|
||||||
case ReceiveTimeout ⇒ context stop self
|
case ReceiveTimeout ⇒ context stop self
|
||||||
case msg ⇒ client forward msg
|
case msg ⇒ client.tell(msg, Actor.noSender)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -546,10 +546,11 @@ object ClusterReceptionist {
|
||||||
*
|
*
|
||||||
* Response messages from the destination actor are tunneled via the receptionist
|
* Response messages from the destination actor are tunneled via the receptionist
|
||||||
* to avoid inbound connections from other cluster nodes to the client, i.e.
|
* to avoid inbound connections from other cluster nodes to the client, i.e.
|
||||||
* the `sender`, as seen by the destination actor, is not the client itself.
|
* the `sender()`, as seen by the destination actor, is not the client itself.
|
||||||
* The `sender` of the response messages, as seen by the client, is preserved
|
* The `sender()` of the response messages, as seen by the client, is `deadLetters`
|
||||||
* as the original sender, so the client can choose to send subsequent messages
|
* since the client should normally send subsequent messages via the `ClusterClient`.
|
||||||
* directly to the actor in the cluster.
|
* It is possible to pass the the original sender inside the reply messages if
|
||||||
|
* the client is supposed to communicate directly to the actor in the cluster.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
final class ClusterReceptionist(pubSubMediator: ActorRef, settings: ClusterReceptionistSettings)
|
final class ClusterReceptionist(pubSubMediator: ActorRef, settings: ClusterReceptionistSettings)
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,13 @@ object ClusterClientSpec extends MultiNodeConfig {
|
||||||
|
|
||||||
testTransport(on = true)
|
testTransport(on = true)
|
||||||
|
|
||||||
|
case class Reply(msg: Any, node: Address)
|
||||||
|
|
||||||
class TestService(testActor: ActorRef) extends Actor {
|
class TestService(testActor: ActorRef) extends Actor {
|
||||||
def receive = {
|
def receive = {
|
||||||
case msg ⇒
|
case msg ⇒
|
||||||
testActor forward msg
|
testActor forward msg
|
||||||
sender() ! msg + "-ack"
|
sender() ! Reply(msg + "-ack", Cluster(context.system).selfAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,7 +118,7 @@ class ClusterClientSpec extends MultiNodeSpec(ClusterClientSpec) with STMultiNod
|
||||||
val c = system.actorOf(ClusterClient.props(
|
val c = system.actorOf(ClusterClient.props(
|
||||||
ClusterClientSettings(system).withInitialContacts(initialContacts)), "client1")
|
ClusterClientSettings(system).withInitialContacts(initialContacts)), "client1")
|
||||||
c ! ClusterClient.Send("/user/testService", "hello", localAffinity = true)
|
c ! ClusterClient.Send("/user/testService", "hello", localAffinity = true)
|
||||||
expectMsg("hello-ack")
|
expectMsgType[Reply].msg should be("hello-ack")
|
||||||
system.stop(c)
|
system.stop(c)
|
||||||
}
|
}
|
||||||
runOn(fourth) {
|
runOn(fourth) {
|
||||||
|
|
@ -190,18 +192,18 @@ class ClusterClientSpec extends MultiNodeSpec(ClusterClientSpec) with STMultiNod
|
||||||
ClusterClientSettings(system).withInitialContacts(initialContacts)), "client2")
|
ClusterClientSettings(system).withInitialContacts(initialContacts)), "client2")
|
||||||
|
|
||||||
c ! ClusterClient.Send("/user/service2", "bonjour", localAffinity = true)
|
c ! ClusterClient.Send("/user/service2", "bonjour", localAffinity = true)
|
||||||
expectMsg("bonjour-ack")
|
val reply = expectMsgType[Reply]
|
||||||
val lastSenderAddress = lastSender.path.address
|
reply.msg should be("bonjour-ack")
|
||||||
val receptionistRoleName = roleName(lastSenderAddress) match {
|
val receptionistRoleName = roleName(reply.node) match {
|
||||||
case Some(r) ⇒ r
|
case Some(r) ⇒ r
|
||||||
case None ⇒ fail("unexpected missing roleName: " + lastSender.path.address)
|
case None ⇒ fail("unexpected missing roleName: " + reply.node)
|
||||||
}
|
}
|
||||||
testConductor.exit(receptionistRoleName, 0).await
|
testConductor.exit(receptionistRoleName, 0).await
|
||||||
remainingServerRoleNames -= receptionistRoleName
|
remainingServerRoleNames -= receptionistRoleName
|
||||||
within(remaining - 3.seconds) {
|
within(remaining - 3.seconds) {
|
||||||
awaitAssert {
|
awaitAssert {
|
||||||
c ! ClusterClient.Send("/user/service2", "hi again", localAffinity = true)
|
c ! ClusterClient.Send("/user/service2", "hi again", localAffinity = true)
|
||||||
expectMsg(1 second, "hi again-ack")
|
expectMsgType[Reply](1 second).msg should be("hi again-ack")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
system.stop(c)
|
system.stop(c)
|
||||||
|
|
@ -220,11 +222,11 @@ class ClusterClientSpec extends MultiNodeSpec(ClusterClientSpec) with STMultiNod
|
||||||
ClusterClientSettings(system).withInitialContacts(initialContacts)), "client3")
|
ClusterClientSettings(system).withInitialContacts(initialContacts)), "client3")
|
||||||
|
|
||||||
c ! ClusterClient.Send("/user/service2", "bonjour2", localAffinity = true)
|
c ! ClusterClient.Send("/user/service2", "bonjour2", localAffinity = true)
|
||||||
expectMsg("bonjour2-ack")
|
val reply = expectMsgType[Reply]
|
||||||
val lastSenderAddress = lastSender.path.address
|
reply.msg should be("bonjour2-ack")
|
||||||
val receptionistRoleName = roleName(lastSenderAddress) match {
|
val receptionistRoleName = roleName(reply.node) match {
|
||||||
case Some(r) ⇒ r
|
case Some(r) ⇒ r
|
||||||
case None ⇒ fail("unexpected missing roleName: " + lastSender.path.address)
|
case None ⇒ fail("unexpected missing roleName: " + reply.node)
|
||||||
}
|
}
|
||||||
// shutdown all but the one that the client is connected to
|
// shutdown all but the one that the client is connected to
|
||||||
remainingServerRoleNames.foreach { r ⇒
|
remainingServerRoleNames.foreach { r ⇒
|
||||||
|
|
@ -244,9 +246,9 @@ class ClusterClientSpec extends MultiNodeSpec(ClusterClientSpec) with STMultiNod
|
||||||
val expectedAddress = node(receptionistRoleName).address
|
val expectedAddress = node(receptionistRoleName).address
|
||||||
awaitAssert {
|
awaitAssert {
|
||||||
c ! ClusterClient.Send("/user/service2", "bonjour3", localAffinity = true)
|
c ! ClusterClient.Send("/user/service2", "bonjour3", localAffinity = true)
|
||||||
expectMsg(1 second, "bonjour3-ack")
|
val reply = expectMsgType[Reply](1 second)
|
||||||
val lastSenderAddress = lastSender.path.address
|
reply.msg should be("bonjour3-ack")
|
||||||
lastSenderAddress should be(expectedAddress)
|
reply.node should be(expectedAddress)
|
||||||
}
|
}
|
||||||
system.stop(c)
|
system.stop(c)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,10 @@ to the named topic.
|
||||||
Response messages from the destination actor are tunneled via the receptionist
|
Response messages from the destination actor are tunneled via the receptionist
|
||||||
to avoid inbound connections from other cluster nodes to the client, i.e.
|
to avoid inbound connections from other cluster nodes to the client, i.e.
|
||||||
the ``sender()``, as seen by the destination actor, is not the client itself.
|
the ``sender()``, as seen by the destination actor, is not the client itself.
|
||||||
The ``sender()`` of the response messages, as seen by the client, is preserved
|
The ``sender()`` of the response messages, as seen by the client, is ``deadLetters``
|
||||||
as the original sender(), so the client can choose to send subsequent messages
|
since the client should normally send subsequent messages via the ``ClusterClient``.
|
||||||
directly to the actor in the cluster.
|
It is possible to pass the the original sender inside the reply messages if
|
||||||
|
the client is supposed to communicate directly to the actor in the cluster.
|
||||||
|
|
||||||
While establishing a connection to a receptionist the ``ClusterClient`` will buffer
|
While establishing a connection to a receptionist the ``ClusterClient`` will buffer
|
||||||
messages and send them when the connection is established. If the buffer is full
|
messages and send them when the connection is established. If the buffer is full
|
||||||
|
|
|
||||||
|
|
@ -297,6 +297,17 @@ is now started as a ``system`` actor instead of a ``user`` actor, i.e. the defau
|
||||||
the ``ClusterClient`` initial contacts has changed to
|
the ``ClusterClient`` initial contacts has changed to
|
||||||
``"akka.tcp://system@hostname:port/system/receptionist"``.
|
``"akka.tcp://system@hostname:port/system/receptionist"``.
|
||||||
|
|
||||||
|
ClusterClient sender
|
||||||
|
====================
|
||||||
|
|
||||||
|
In 2.3 the ``sender()`` of the response messages, as seen by the client, was the
|
||||||
|
actor in cluster.
|
||||||
|
|
||||||
|
In 2.4 the ``sender()`` of the response messages, as seen by the client, is ``deadLetters``
|
||||||
|
since the client should normally send subsequent messages via the ``ClusterClient``.
|
||||||
|
It is possible to pass the the original sender inside the reply messages if
|
||||||
|
the client is supposed to communicate directly to the actor in the cluster.
|
||||||
|
|
||||||
Akka Persistence
|
Akka Persistence
|
||||||
================
|
================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,10 @@ to the named topic.
|
||||||
Response messages from the destination actor are tunneled via the receptionist
|
Response messages from the destination actor are tunneled via the receptionist
|
||||||
to avoid inbound connections from other cluster nodes to the client, i.e.
|
to avoid inbound connections from other cluster nodes to the client, i.e.
|
||||||
the ``sender()``, as seen by the destination actor, is not the client itself.
|
the ``sender()``, as seen by the destination actor, is not the client itself.
|
||||||
The ``sender()`` of the response messages, as seen by the client, is preserved
|
The ``sender()`` of the response messages, as seen by the client, is ``deadLetters``
|
||||||
as the original sender(), so the client can choose to send subsequent messages
|
since the client should normally send subsequent messages via the ``ClusterClient``.
|
||||||
directly to the actor in the cluster.
|
It is possible to pass the the original sender inside the reply messages if
|
||||||
|
the client is supposed to communicate directly to the actor in the cluster.
|
||||||
|
|
||||||
While establishing a connection to a receptionist the ``ClusterClient`` will buffer
|
While establishing a connection to a receptionist the ``ClusterClient`` will buffer
|
||||||
messages and send them when the connection is established. If the buffer is full
|
messages and send them when the connection is established. If the buffer is full
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue