- Changed implementation of Actor.actorOf to work in the the new world of cluster.ref, cluster.use and cluster.store.
- Changed semantics of replica config. Default replicas is now 0. Replica 1 means one copy of the actor is instantiated on another node. - Actor.remote.actorFor/Actor.remote.register is now separated and orthogonal from cluster implementation. - cluster.ref now creates and instantiates its replicas automatically, e.g. it can be created first and will then set up what it needs. - Added logging everywhere, better warning messages etc. - Each node now fetches the whole deployment configuration from the cluster on boot. - Added some config options to cluster Signed-off-by: Jonas Bonér <jonasremove@jonasboner.com>
This commit is contained in:
parent
71beab820c
commit
e6fa55b3a8
15 changed files with 328 additions and 217 deletions
|
|
@ -28,6 +28,7 @@ import akka.util._
|
|||
import Helpers._
|
||||
import akka.actor._
|
||||
import Actor._
|
||||
import Status._
|
||||
import akka.event.EventHandler
|
||||
import akka.dispatch.{ Dispatchers, Future }
|
||||
import akka.remoteinterface._
|
||||
|
|
@ -124,6 +125,8 @@ object Cluster {
|
|||
val maxTimeToWaitUntilConnected = Duration(config.getInt("akka.cluster.max-time-to-wait-until-connected", 30), TIME_UNIT).toMillis.toInt
|
||||
val shouldCompressData = config.getBool("akka.cluster.use-compression", false)
|
||||
val enableJMX = config.getBool("akka.enable-jmx", true)
|
||||
val remoteDaemonAckTimeout = Duration(config.getInt("akka.cluster.remote-daemon-ack-timeout", 30), TIME_UNIT).toMillis.toInt
|
||||
val excludeRefNodeInReplicaSet = config.getBool("akka.cluster.exclude-ref-node-in-replica-set", true)
|
||||
|
||||
@volatile
|
||||
private var properties = Map.empty[String, String]
|
||||
|
|
@ -518,7 +521,7 @@ class DefaultClusterNode private[akka] (
|
|||
|
||||
val uuid = actorRef.uuid
|
||||
EventHandler.debug(this,
|
||||
"Clustering actor [%s] with UUID [%s]".format(actorRef.address, uuid))
|
||||
"Storing actor [%s] with UUID [%s] in cluster".format(actorRef.address, uuid))
|
||||
|
||||
val actorBytes = if (shouldCompressData) LZF.compress(toBinary(actorRef, serializeMailbox)(format))
|
||||
else toBinary(actorRef)(format)
|
||||
|
|
@ -565,12 +568,30 @@ class DefaultClusterNode private[akka] (
|
|||
ignore[ZkNodeExistsException](zkClient.createPersistent("%s/%s".format(actorAddressToUuidsPathFor(actorRef.address), uuid)))
|
||||
}
|
||||
|
||||
import RemoteClusterDaemon._
|
||||
val command = RemoteDaemonMessageProtocol.newBuilder
|
||||
.setMessageType(USE)
|
||||
.setActorUuid(uuidToUuidProtocol(uuid))
|
||||
.build
|
||||
|
||||
replicaConnectionsForReplicationFactor(replicationFactor) foreach { connection ⇒
|
||||
connection ! command
|
||||
(connection !! (command, remoteDaemonAckTimeout)) match {
|
||||
|
||||
case Some(Success) ⇒
|
||||
EventHandler.debug(this,
|
||||
"Replica for [%s] successfully created on [%s]"
|
||||
.format(actorRef.address, connection))
|
||||
|
||||
case Some(Failure(cause)) ⇒
|
||||
EventHandler.error(cause, this, cause.toString)
|
||||
throw cause
|
||||
|
||||
case None ⇒
|
||||
val error = new ClusterException(
|
||||
"Operation to instantiate replicas throughout the cluster timed out, cause of error unknow")
|
||||
EventHandler.error(error, this, error.toString)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
this
|
||||
|
|
@ -596,7 +617,7 @@ class DefaultClusterNode private[akka] (
|
|||
def remove(address: String): ClusterNode = {
|
||||
isConnected ifOn {
|
||||
EventHandler.debug(this,
|
||||
"Removing actor(s) with ADDRESS [%s] from cluster".format(address))
|
||||
"Removing actor(s) with address [%s] from cluster".format(address))
|
||||
uuidsForActorAddress(address) foreach (uuid ⇒ remove(uuid))
|
||||
}
|
||||
this
|
||||
|
|
@ -641,7 +662,8 @@ class DefaultClusterNode private[akka] (
|
|||
|
||||
actorUuidsForActorAddress(actorAddress) map { uuid ⇒
|
||||
EventHandler.debug(this,
|
||||
"Checking out actor with UUID [%s] to be used on node [%s]".format(uuid, nodeAddress.nodeName))
|
||||
"Checking out actor with UUID [%s] to be used on node [%s] as local actor"
|
||||
.format(uuid, nodeAddress.nodeName))
|
||||
|
||||
ignore[ZkNodeExistsException](zkClient.createPersistent(actorAtNodePathFor(nodeAddress.nodeName, uuid), true))
|
||||
ignore[ZkNodeExistsException](zkClient.createEphemeral(actorLocationsPathFor(uuid, nodeAddress)))
|
||||
|
|
@ -750,34 +772,14 @@ class DefaultClusterNode private[akka] (
|
|||
* Creates an ActorRef with a Router to a set of clustered actors.
|
||||
*/
|
||||
def ref(actorAddress: String, router: RouterType): ActorRef = if (isConnected.isOn) {
|
||||
|
||||
val addresses = addressesForActor(actorAddress)
|
||||
|
||||
EventHandler.debug(this,
|
||||
"Creating cluster actor ref with router [%s] for actors [%s]".format(router, addresses.mkString(", ")))
|
||||
"Checking out cluster actor ref with address [%s] and router [%s] connected to [\n\t%s]"
|
||||
.format(actorAddress, router, addresses.mkString("\n\t")))
|
||||
|
||||
def registerClusterActorRefForAddress(actorRef: ClusterActorRef, addresses: Array[(UUID, InetSocketAddress)]) {
|
||||
addresses foreach {
|
||||
case (_, address) ⇒ clusterActorRefs.put(address, actorRef)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME remove?
|
||||
def refByUuid(uuid: UUID): ActorRef = {
|
||||
val actor = Router newRouter (router, addresses, uuidToString(uuid), Actor.TIMEOUT)
|
||||
registerClusterActorRefForAddress(actor, addresses)
|
||||
actor
|
||||
}
|
||||
|
||||
def refByAddress(actorAddress: String): ActorRef = {
|
||||
//FIXME: unused uuids
|
||||
val uuids = uuidsForActorAddress(actorAddress)
|
||||
val actor = Router newRouter (router, addresses, actorAddress, Actor.TIMEOUT)
|
||||
registerClusterActorRefForAddress(actor, addresses)
|
||||
actor
|
||||
}
|
||||
|
||||
refByAddress(actorAddress).start()
|
||||
val actorRef = Router newRouter (router, addresses, actorAddress, Actor.TIMEOUT)
|
||||
addresses foreach { case (_, address) ⇒ clusterActorRefs.put(address, actorRef) }
|
||||
actorRef.start()
|
||||
|
||||
} else throw new ClusterException("Not connected to cluster")
|
||||
|
||||
|
|
@ -1103,7 +1105,8 @@ class DefaultClusterNode private[akka] (
|
|||
new InetSocketAddress(hostname, port)
|
||||
}
|
||||
|
||||
private def actorUuidsForActorAddress(actorAddress: String): Array[UUID] = uuidsForActorAddress(actorAddress) filter (_ ne null)
|
||||
private def actorUuidsForActorAddress(actorAddress: String): Array[UUID] =
|
||||
uuidsForActorAddress(actorAddress) filter (_ ne null)
|
||||
|
||||
/**
|
||||
* Returns a random set with replica connections of size 'replicationFactor'.
|
||||
|
|
@ -1113,7 +1116,7 @@ class DefaultClusterNode private[akka] (
|
|||
var replicas = HashSet.empty[ActorRef]
|
||||
if (replicationFactor < 1) return replicas
|
||||
|
||||
connectToAllReplicas()
|
||||
connectToAllMembershipNodesInCluster()
|
||||
|
||||
val numberOfReplicas = replicaConnections.size
|
||||
val replicaConnectionsAsArray = replicaConnections.toList map {
|
||||
|
|
@ -1138,10 +1141,14 @@ class DefaultClusterNode private[akka] (
|
|||
/**
|
||||
* Connect to all available replicas unless already connected).
|
||||
*/
|
||||
private def connectToAllReplicas() {
|
||||
private def connectToAllMembershipNodesInCluster() {
|
||||
val runOnThisNode = false // (node: String) ⇒ !excludeRefNodeInReplicaSet && node != Config.nodename
|
||||
membershipNodes foreach { node ⇒
|
||||
if (!replicaConnections.contains(node)) {
|
||||
// if (runOnThisNode(node) && !replicaConnections.contains(node)) { // only connect to each replica once
|
||||
if (!replicaConnections.contains(node)) { // only connect to each replica once
|
||||
val address = addressForNode(node)
|
||||
EventHandler.debug(this,
|
||||
"Connecting to replica with nodename [%s] and address [%s]".format(node, address))
|
||||
val clusterDaemon = Actor.remote.actorFor(RemoteClusterDaemon.ADDRESS, address.getHostName, address.getPort)
|
||||
replicaConnections.put(node, (address, clusterDaemon))
|
||||
}
|
||||
|
|
@ -1453,6 +1460,8 @@ object RemoteClusterDaemon {
|
|||
val functionServerDispatcher = Dispatchers.newDispatcher("akka:cloud:cluster:function:server").build
|
||||
}
|
||||
|
||||
// FIXME supervise RemoteClusterDaemon
|
||||
|
||||
/**
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
|
|
@ -1466,28 +1475,42 @@ class RemoteClusterDaemon(cluster: ClusterNode) extends Actor {
|
|||
def receive: Receive = {
|
||||
case message: RemoteDaemonMessageProtocol ⇒
|
||||
EventHandler.debug(this, "Received command to RemoteClusterDaemon [%s]".format(message))
|
||||
|
||||
message.getMessageType match {
|
||||
|
||||
case USE ⇒
|
||||
if (message.hasActorUuid) {
|
||||
val uuid = uuidProtocolToUuid(message.getActorUuid)
|
||||
val address = cluster.actorAddressForUuid(uuid)
|
||||
implicit val format: Serializer = cluster formatForActor address
|
||||
val actors = cluster use address
|
||||
} else if (message.hasActorAddress) {
|
||||
val address = message.getActorAddress
|
||||
implicit val format: Serializer = cluster formatForActor address
|
||||
val actors = cluster use address
|
||||
} else EventHandler.warning(this,
|
||||
"None of 'uuid', or 'address' is specified, ignoring remote cluster daemon command [%s]".format(message))
|
||||
try {
|
||||
if (message.hasActorUuid) {
|
||||
val uuid = uuidProtocolToUuid(message.getActorUuid)
|
||||
val address = cluster.actorAddressForUuid(uuid)
|
||||
implicit val format: Serializer = cluster formatForActor address
|
||||
val actors = cluster use address
|
||||
} else if (message.hasActorAddress) {
|
||||
val address = message.getActorAddress
|
||||
implicit val format: Serializer = cluster formatForActor address
|
||||
val actors = cluster use address
|
||||
} else {
|
||||
EventHandler.warning(this,
|
||||
"None of 'uuid', or 'address' is specified, ignoring remote cluster daemon command [%s]"
|
||||
.format(message))
|
||||
}
|
||||
self.reply(Success)
|
||||
} catch {
|
||||
case error ⇒
|
||||
self.reply(Failure(error))
|
||||
throw error
|
||||
}
|
||||
|
||||
case RELEASE ⇒
|
||||
if (message.hasActorUuid) {
|
||||
cluster release cluster.actorAddressForUuid(uuidProtocolToUuid(message.getActorUuid))
|
||||
} else if (message.hasActorAddress) {
|
||||
cluster release message.getActorAddress
|
||||
} else EventHandler.warning(this,
|
||||
"None of 'uuid' or 'actorAddress'' is specified, ignoring remote cluster daemon command [%s]".format(message))
|
||||
} else {
|
||||
EventHandler.warning(this,
|
||||
"None of 'uuid' or 'actorAddress'' is specified, ignoring remote cluster daemon command [%s]"
|
||||
.format(message))
|
||||
}
|
||||
|
||||
case START ⇒ cluster.start()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue