Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deadlock when initializing Akka cluster: document minimum thread pool size #17253

Closed
clockfly opened this issue Apr 22, 2015 · 22 comments
Closed
Milestone

Comments

@clockfly
Copy link

Problem: Timeout when akka cluster trying to create the Cluster extension.

Frequency: random

java.util.concurrent.TimeoutException: Futures timed out after [60000 milliseconds]
        at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:219)
        at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:223)
        at scala.concurrent.Await$$anonfun$result$1.apply(package.scala:116)
        at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
        at scala.concurrent.Await$.result(package.scala:116)
        at akka.cluster.Cluster.liftedTree1$1(Cluster.scala:172)
        at akka.cluster.Cluster.<init>(Cluster.scala:171)
        at akka.cluster.Cluster$.createExtension(Cluster.scala:42)
        at akka.cluster.Cluster$.createExtension(Cluster.scala:37)
        at akka.actor.ActorSystemImpl.registerExtension(ActorSystem.scala:711)
        at akka.actor.ExtensionId$class.apply(Extension.scala:79)
        at akka.cluster.Cluster$.apply(Cluster.scala:37)
        at 
     ......
akka.cluster.ClusterActorRefProvider.createRemoteWatcher(ClusterActorRefProvider.scala:66)
        at akka.remote.RemoteActorRefProvider.init(RemoteActorRefProvider.scala:186)
        at akka.cluster.ClusterActorRefProvider.init(ClusterActorRefProvider.scala:58)
        at akka.actor.ActorSystemImpl.liftedTree2$1(ActorSystem.scala:618)
        at akka.actor.ActorSystemImpl._start$lzycompute(ActorSystem.scala:615)
        at akka.actor.ActorSystemImpl._start(ActorSystem.scala:615)
        at akka.actor.ActorSystemImpl.start(ActorSystem.scala:632)
        at akka.actor.ActorSystem$.apply(ActorSystem.scala:141)
        at akka.actor.ActorSystem$.apply(ActorSystem.scala:118)

Investigation

The timeout happen in class Cluster, when trying to GetClusterCoreRef

  private[cluster] val clusterCore: ActorRef = {
    implicit val timeout = system.settings.CreationTimeout
    try {
      Await.result((clusterDaemons ? InternalClusterAction.GetClusterCoreRef).mapTo[ActorRef], timeout.duration)
    } catch {

that lead to

private[cluster] final class ClusterCoreSupervisor extends Actor with ActorLogging
  with RequiresMessageQueue[UnboundedMessageQueueSemantics] {

...
val coreDaemon = context.watch(context.actorOf(Props(classOf[ClusterCoreDaemon], publisher).
    withDispatcher(context.props.dispatcher), name = "daemon"))
...
def receive = {
    case InternalClusterAction.GetClusterCoreRef ⇒ sender() ! coreDaemon
  }
...
}

ClusterCoreSupervisor will reply ClusterCoreDaemon

The problem is that ClusterCoreDaemon also requires the Cluster extension is initialized.
Check the defiition of ClusterCoreDaemon:

private[cluster] class ClusterCoreDaemon(publisher: ActorRef) extends Actor with ActorLogging
  with RequiresMessageQueue[UnboundedMessageQueueSemantics] {
  import InternalClusterAction._

  val cluster = Cluster(context.system)

val cluster = Cluster(context.system) will call system.registerExtension, which is where the exception stack is waiting for.

update on 4/22

The updated analysis is on comment #17253 (comment)

@patriknw
Copy link
Member

The problem is not in the ClusterCoreDaemon, because the GetClusterCoreRef is replied to by the parent ClusterCoreSupervisor.

What is your configuration? Can you share a way to reproduce it (random frequency is alright)?

@clockfly
Copy link
Author

My configuration

  extensions = [
    "akka.contrib.datareplication.DataReplication$"
  ]

  akka {

    cluster {
      roles = ["master"]
      auto-down-unreachable-after = 15s
    }

    loglevel = "INFO"
    log-dead-letters = off
    log-dead-letters-during-shutdown = off

    actor {
      ## Master forms a akka cluster
      provider = "akka.cluster.ClusterActorRefProvider"

      creation-timeout = 60s

      provider = "akka.remote.RemoteActorRefProvider"
      default-mailbox {
        mailbox-type = "akka.dispatch.SingleConsumerOnlyUnboundedMailbox"
      }
      default-dispatcher {
        mailbox-type = "akka.dispatch.SingleConsumerOnlyUnboundedMailbox"
        throughput = 10
        fork-join-executor {
          parallelism-factor = 2
          parallelism-max = 2
          parallelism-min = 1
        }
      }
    }
    remote {

      log-remote-lifecycle-events = on
      #    use-dispatcher = ""
      use-dispatcher = "akka.remote.default-remote-dispatcher"
      enabled-transports = ["akka.remote.netty.tcp"]
      netty.tcp {
        port = 0
        hostname = "127.0.0.1"
        server-socket-worker-pool {
          pool-size-min = 1
          pool-size-max = 2
        }
        client-socket-worker-pool {
          pool-size-min = 1
          pool-size-max = 2
        }
      }
      default-remote-dispatcher {
        throughput = 5
        type = Dispatcher
        mailbox-type = "akka.dispatch.SingleConsumerOnlyUnboundedMailbox"
        executor = "fork-join-executor"
        fork-join-executor {
          parallelism-min = 1
          parallelism-max = 2
        }
      }
      startup-timeout = 600 s
      shutdown-timeout = 600 s
      flush-wait-on-shutdown = 2 s
      command-ack-timeout = 600 s

      transport-failure-detector {
        heartbeat-interval = 600 s
        acceptable-heartbeat-pause = 2000 s
      }
      watch-failure-detector {
        heartbeat-interval = 600 s
        acceptable-heartbeat-pause = 10 s
        unreachable-nodes-reaper-interval = 600s
        expected-response-after = 3 s
      }
      retry-gate-closed-for = 5 s
      prune-quarantine-marker-after = 5 d
      system-message-ack-piggyback-timeout = 600 s
      resend-interval = 600 s
      initial-system-message-delivery-timeout = 3 m
      enabled-transports = ["akka.remote.netty.tcp"]
      netty.tcp.connection-timeout = 600 s
    }
  }

@clockfly clockfly changed the title dead lock when initializing Akka cluster timeout when initializing Akka cluster Apr 22, 2015
@clockfly
Copy link
Author

Test code is very simple

import akka.actor.ActorSystem
import org.apache.gearpump.cluster.TestUtil

object BB extends App {

  val config = TestUtil.MASTER_CONFIG

  (0 until 1000).foreach {i =>
    val system = ActorSystem(s"test$i", config)
    system.shutdown()
  }
}

I will try to get some stack trace

@clockfly clockfly changed the title timeout when initializing Akka cluster deadlock when initializing Akka cluster Apr 22, 2015
@clockfly
Copy link
Author

I now have the stacktrace

It is clear now why deadlock happen.

2015-04-22 22:11:15
Full thread dump Java HotSpot(TM) Client VM (20.45-b01 mixed mode, sharing):

"test164-akka.actor.default-dispatcher-3" daemon prio=6 tid=0x05579c00 nid=0x2458 waiting on condition [0x05f0f000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x24761768> (a java.util.concurrent.CountDownLatch$Sync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:969)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1281)
    at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:207)
    at akka.actor.ActorSystemImpl.findExtension(ActorSystem.scala:699)
    at akka.actor.ActorSystemImpl.registerExtension(ActorSystem.scala:706)
    at akka.actor.ExtensionId$class.apply(Extension.scala:79)
    at akka.cluster.Cluster$.apply(Cluster.scala:37)
    at akka.cluster.ClusterCoreDaemon.<init>(ClusterDaemon.scala:220)
    at sun.reflect.GeneratedConstructorAccessor32.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at akka.util.Reflect$.instantiate(Reflect.scala:66)
    at akka.actor.ArgsReflectConstructor.produce(Props.scala:352)
    at akka.actor.Props.newActor(Props.scala:252)
    at akka.actor.ActorCell.newActor(ActorCell.scala:552)
    at akka.actor.ActorCell.create(ActorCell.scala:578)
    at akka.actor.ActorCell.invokeAll$1(ActorCell.scala:456)
    at akka.actor.ActorCell.systemInvoke(ActorCell.scala:478)
    at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:263)
    at akka.dispatch.Mailbox.run(Mailbox.scala:219)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

   Locked ownable synchronizers:
    - None

"test164-akka.actor.default-dispatcher-2" daemon prio=6 tid=0x0557c000 nid=0x335c waiting on condition [0x05ccf000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x24761768> (a java.util.concurrent.CountDownLatch$Sync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:969)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1281)
    at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:207)
    at akka.actor.ActorSystemImpl.findExtension(ActorSystem.scala:699)
    at akka.actor.ActorSystemImpl.registerExtension(ActorSystem.scala:706)
    at akka.actor.ExtensionId$class.apply(Extension.scala:79)
    at akka.cluster.Cluster$.apply(Cluster.scala:37)
    at akka.cluster.ClusterHeartbeatReceiver.<init>(ClusterHeartbeat.scala:23)
    at sun.reflect.GeneratedConstructorAccessor30.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at java.lang.Class.newInstance0(Class.java:357)
    at java.lang.Class.newInstance(Class.java:310)
    at akka.util.Reflect$.instantiate(Reflect.scala:45)
    at akka.actor.NoArgsReflectConstructor.produce(Props.scala:361)
    at akka.actor.Props.newActor(Props.scala:252)
    at akka.actor.ActorCell.newActor(ActorCell.scala:552)
    at akka.actor.ActorCell.create(ActorCell.scala:578)
    at akka.actor.ActorCell.invokeAll$1(ActorCell.scala:456)
    at akka.actor.ActorCell.systemInvoke(ActorCell.scala:478)
    at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:263)
    at akka.dispatch.Mailbox.run(Mailbox.scala:219)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

   Locked ownable synchronizers:
    - None

"main" prio=6 tid=0x00e3f800 nid=0x1b40 waiting on condition [0x003ff000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x24832cd0> (a scala.concurrent.impl.Promise$CompletionLatch)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos(AbstractQueuedSynchronizer.java:1011)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(AbstractQueuedSynchronizer.java:1303)
    at scala.concurrent.impl.Promise$DefaultPromise.tryAwait(Promise.scala:208)
    at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:218)
    at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:223)
    at scala.concurrent.Await$$anonfun$result$1.apply(package.scala:116)
    at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
    at scala.concurrent.Await$.result(package.scala:116)
    at akka.cluster.Cluster.liftedTree1$1(Cluster.scala:172)
    at akka.cluster.Cluster.<init>(Cluster.scala:171)
    at akka.cluster.Cluster$.createExtension(Cluster.scala:42)
    at akka.cluster.Cluster$.createExtension(Cluster.scala:37)
    at akka.actor.ActorSystemImpl.registerExtension(ActorSystem.scala:711)
    at akka.actor.ExtensionId$class.apply(Extension.scala:79)
    at akka.cluster.Cluster$.apply(Cluster.scala:37)
    at akka.cluster.ClusterActorRefProvider.createRemoteWatcher(ClusterActorRefProvider.scala:66)
    at akka.remote.RemoteActorRefProvider.init(RemoteActorRefProvider.scala:186)
    at akka.cluster.ClusterActorRefProvider.init(ClusterActorRefProvider.scala:58)
    at akka.actor.ActorSystemImpl.liftedTree2$1(ActorSystem.scala:618)
    at akka.actor.ActorSystemImpl._start$lzycompute(ActorSystem.scala:615)
    - locked <0x246558b0> (a akka.actor.ActorSystemImpl)
    at akka.actor.ActorSystemImpl._start(ActorSystem.scala:615)
    at akka.actor.ActorSystemImpl.start(ActorSystem.scala:632)
    at akka.actor.ActorSystem$.apply(ActorSystem.scala:141)
    at akka.actor.ActorSystem$.apply(ActorSystem.scala:118)
    at org.apache.gearpump.services.BB$.delayedEndpoint$org$apache$gearpump$services$BB$1(BB.scala:10)
    at org.apache.gearpump.services.BB$delayedInit$body.apply(BB.scala:6)
    at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
    at scala.App$$anonfun$main$1.apply(App.scala:76)
    at scala.App$$anonfun$main$1.apply(App.scala:76)
    at scala.collection.immutable.List.foreach(List.scala:381)
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
    at scala.App$class.main(App.scala:76)
    at org.apache.gearpump.services.BB$.main(BB.scala:6)
    at org.apache.gearpump.services.BB.main(BB.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

   Locked ownable synchronizers:
    - None

@clockfly
Copy link
Author

I have configured the default-dispather pool size to be 2.

From the stack trace, one dispatcher thread is hang by initialization process of ClusterCoreDaemon, another is hang by constructor of ClusterHeartbeatReceiver.

As ClusterCoreDaemon and ClusterHeartbeatReceiver have occupied all two slots of the dispatcher pool, ClusterDaemon.receive cannot get scheduled to response to (clusterDaemons ? InternalClusterAction.GetClusterCoreRef) in main thread.

So, main thread is waiting for ClusterDaemon to be scheduled, and lead to wait for ClusterCoreDaemon or ClusterHeartbeatReceiver to release thread.

While ClusterCoreDaemon or ClusterHeartbeatReceiver is waiting for Cluster extension to be initialized, and lead to wait for main thread complete initializing of Cluster extension.

That create a dependency relation of: A(main thread) -> B (ClusterDaemon) -> C(ClusterCoreDaemon) , C(ClusterCoreDaemon)->A(main thread)

A typical dead lock.

@drewhk
Copy link
Member

drewhk commented Apr 22, 2015

heh, the few blocking calls that we have in startup. We should be able to run with one thread in principle, so we need to think about these.

@clockfly
Copy link
Author

I also tried to configure the thread pool size to 3, the issue still exists, but less likely to happen.

I found another class, ClusterMetricsCollector, which will also using Cluster extension and block the thread.

There may exist other classes, so simplify changing the default-dispather number may not work, we need a complete fix for this.

This issue is bothering me everyday, suddenly a nightly UT fails :)

@drewhk
Copy link
Member

drewhk commented Apr 22, 2015

Yes it needs to be fixed, I think it should work with one thread. Easy to add a test though to enforce this, thanks for the reproducer!

@He-Pin
Copy link
Member

He-Pin commented Apr 22, 2015

then make sure akka could run on a single thread pool.

@drewhk
Copy link
Member

drewhk commented Apr 22, 2015

That is what I said :)

@rkuhn rkuhn added 0 - new Ticket is unclear on it's purpose or if it is valid or not t:cluster labels Apr 23, 2015
@rkuhn
Copy link
Contributor

rkuhn commented Apr 23, 2015

Whether the ClusterCoreDaemon blocks in its initialization or not does not affect the ClusterCoreSupervisor since that happens on a different thread. If you are observing a real dead lock I suspect that you have configured the cluster dispatcher with too few threads (the default works just fine). What is not entirely clear to me is what your observation is, in case of a dead lock please post a full JVM stack trace.

@clockfly
Copy link
Author

@rkuhn

Thank you for the reply. Yes, it is due to the dispatcher thread is not enough(verified default dispatcher thread pool size <= 3 will cause dead lock).

I have updated the analysis on #17253 (comment)

I think the stack trace is clear enough when combined with comment at #17253 (comment)

@patriknw
Copy link
Member

Can you give us an motivation why it is important to be able to run akka with less than 3 threads?

We could have a startup error message for this kind of misconfiguration, though.

@rkuhn
Copy link
Contributor

rkuhn commented Apr 23, 2015

Yes, we should document this in reference.conf, in the dispatcher documentation and in the timeout exception that gets thrown during ActorSystem creation in this case.

@rkuhn rkuhn changed the title deadlock when initializing Akka cluster deadlock when initializing Akka cluster: document minimum thread pool size Apr 23, 2015
@rkuhn rkuhn added 1 - triaged Tickets that are safe to pick up for contributing in terms of likeliness of being accepted t:docs t:core and removed 0 - new Ticket is unclear on it's purpose or if it is valid or not labels Apr 23, 2015
@rkuhn rkuhn added this to the 2.3.x milestone Apr 23, 2015
@drewhk
Copy link
Member

drewhk commented Apr 23, 2015

I am not sure. Why cannot we run on 1 thread? I mean, we can work around by documenting this, but I still feel uneasy about this.

@clockfly
Copy link
Author

@patriknw

Can you give us an motivation why it is important to be able to run akka with less than 3 threads?

3 threads is the just test environment I used to reproduce this problem. It is possible that the deadlock stil exist after allocating more threads in default-dispatcher.

I did a source code search in akka cluster, there are 12 actor class definition which will wait the extension to be initialized when created, which make me believe it is possible that the deadblock still exist for 4 dispatcher threads or more. So, I am not sure whether documenting is the right approach to solve this.

here is a list of class which will wait for the Cluster extension in class construction.

ClusterCoreDaemon
FirstSeedNodeProcess
JoinSeedNodeProcess
OnMemberUpListener
ClusterHeartbeatReceiver
ClusterHeartbeatSender
ClusterMetricsCollector
JmxMetricsCollector
ClusterRemoteWatcher
AutoDown
AdaptiveLoadBalancingRoutingLogic
AdaptiveLoadBalancingMetricsListener

@patriknw
Copy link
Member

@clockfly I see what you mean. I will take a look at the hierarchy of those actors and check that not more than necessary are started while initializing the cluster extension.

@hosamaly
Copy link

I wonder whether there has been any update regarding this issue...

I'm trying to use a CallingThreadDispatcher as the default-dispatcher for my tests, but it's blocking at startup because of this deadlock. Is there any solution or workaround to get it to work?

@rkuhn
Copy link
Contributor

rkuhn commented Jul 15, 2015 via email

@hosamaly
Copy link

@rkuhn I was hoping it could make it easier to make sure my tests execute in a deterministic order. I am already using TestActorRef, but it seems that it doesn't work with persistent actors.

I was commenting on this issue because the stack trace is somewhat similar (ending at findExtension), but I'll try to look for a different way.

Thanks for your advice!

@rkuhn
Copy link
Contributor

rkuhn commented Jul 15, 2015

Running the tests in a completely different fashion than the production code may give you good test results, but be aware that then you are not really testing what you deploy. If tests fail due to non-deterministic timing or execution order then that points out weaknesses in either your tests (assuming too much) or your code (providing too little). In any case it will lead to better code to fix these issues rather than trying to “avoid” them in tests.

@patriknw patriknw modified the milestones: 2.4.0-RC2, 2.3.x Aug 27, 2015
@patriknw patriknw added 3 - in progress Someone is working on this ticket and removed 1 - triaged Tickets that are safe to pick up for contributing in terms of likeliness of being accepted t:core t:docs labels Aug 27, 2015
patriknw added a commit that referenced this issue Aug 27, 2015
When using a dispatcher (default or separate cluster dispatcher)
with less than 5 threads the Cluster extension initialization
could deadlock.

It was reproducable by adding a sleep before the Await of GetClusterCoreRef
in the Cluster extension constructor. The reason was that other cluster actors were
started too early and they also tried to get the Cluster extension and thereby blocking
dispatcher threads.

Note that the Cluster extension is started via ClusterActorRefProvider before
ActorSystem.apply returns.

The improvement is to start the cluster child actors lazily when the
GetClusterCoreRef is received.
@patriknw
Copy link
Member

I have finally got around to improving this. See description in PR #18332.
Now it is possible to start cluster with dispatcher with 1 thread, previously 5 threads were required to avoid the risk of deadlock.

patriknw added a commit that referenced this issue Sep 3, 2015
When using a dispatcher (default or separate cluster dispatcher)
with less than 5 threads the Cluster extension initialization
could deadlock.

It was reproducable by adding a sleep before the Await of GetClusterCoreRef
in the Cluster extension constructor. The reason was that other cluster actors were
started too early and they also tried to get the Cluster extension and thereby blocking
dispatcher threads.

Note that the Cluster extension is started via ClusterActorRefProvider before
ActorSystem.apply returns.

The improvement is to start the cluster child actors lazily when the
GetClusterCoreRef is received.
patriknw added a commit that referenced this issue Sep 3, 2015
@patriknw patriknw removed the 3 - in progress Someone is working on this ticket label Sep 3, 2015
@patriknw patriknw closed this as completed Sep 3, 2015
patriknw added a commit that referenced this issue Sep 3, 2015
…patriknw

=clu #17253 Warn about too small cluster dispatcher
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants