Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ClassCastException: interface akka.actor.Scheduler is not assignable from class akka.actor.LightArrayRevolverScheduler

I am trying to run something I have been successfully running under a variety of conditions for months. I am using akka-actor_2.11 2.3.4 with scala-library 2.11.7 from a Java application running Java 7. Like I said, the same code has worked for months. Under the most recent circumstances, I am getting the following:

java.lang.ClassCastException: interface akka.actor.Scheduler is not assignable from class akka.actor.LightArrayRevolverScheduler
at akka.actor.ReflectiveDynamicAccess$$anonfun$getClassFor$1.apply(DynamicAccess.scala:69)
at akka.actor.ReflectiveDynamicAccess$$anonfun$getClassFor$1.apply(DynamicAccess.scala:66)
at scala.util.Try$.apply(Try.scala:192)
at akka.actor.ReflectiveDynamicAccess.getClassFor(DynamicAccess.scala:66)
at akka.actor.ReflectiveDynamicAccess.createInstanceFor(DynamicAccess.scala:84)
at akka.actor.ActorSystemImpl.createScheduler(ActorSystem.scala:677)
at akka.actor.ActorSystemImpl.<init>(ActorSystem.scala:576)
at akka.actor.ActorSystem$.apply(ActorSystem.scala:142)
at akka.actor.ActorSystem$.apply(ActorSystem.scala:109)
at akka.actor.ActorSystem$.create(ActorSystem.scala:57)
at akka.actor.ActorSystem.create(ActorSystem.scala)

The call in question is: system= ActorSystem.create("MyActorSystem");

This call happens in the constructor for a class, which is loaded dynamically, via reflection ala getConstructor(...).newInstance(...).

The issue has arisen when a user of the distributed computation environment I wrote that this is based on tries to execute a job that dynamically instantiates a job that dynamically instantiates a job (2 levels of reflective instantiation). Basically, something like this pseudo call list :

reflectivelyCreate(job)
job.reflectivelyCreate(job2)
job2.instantiateActorSystem()
<fail>

If I run the exact same code in the following manner:

reflectivelyCreate(job2)
job2.instantiateActorSystem()
<success>

Everything works.

My question is whether there is some stateful class loader-related magic happening behind-the-scenes in Java such that Akka's assumptions about its state are incorrect. Similar issues I found (Akka ActorSystem creation issue) seemed to have to do with threading / scala repl invocation, but my code is single-threaded, and invoked the same way in both the success and failure cases above. The problematic invocation occurs only with a difference in the depth of the call stack as far as I can tell so far.

I would appreciate any input from akka gurus!

like image 355
mephicide Avatar asked Mar 29 '16 17:03

mephicide


1 Answers

If anyone else stumbles across this; the problem in my case was that I was using a scala interpreter within the same process that might also make use of Akka. Other multiple-classloader scenarios may exhibit the same issue. Here is the fix for my case:

  • Save the classloader I like (the one that loaded akka libraries) in a static field upon program initialization with private static ClassLoader ourClassLoader = CmdLineMain.class.getClassLoader();
  • After using the scala interpreter (which apparently replaces the classloader with one it likes), call Thread.currentThread().setContextClassLoader(ourClassLoader);

My program is single-threaded, but there are certainly other ways to solve the problem such that each thread maintains its own loader. That is beyond the scope of this post ;)

like image 160
mephicide Avatar answered Sep 28 '22 11:09

mephicide