java.lang.IllegalStateException: Trying to materialize stream after materializer has been shutdown

Viewed 1414

My app is based on the Scala Play framework and it has a scheduled Job that runs every time the app is loaded:

// code snippet:

actorSystem.scheduler.schedule(initialDelay = 0.second, interval = intervalSeconds.second)

During tests if I enable the scheduled job all the tests finishes OK and the result is passed(green) but I see an exception randomly showing up in the logs:

[TaskInvocation] Trying to materialize stream after materializer has been shutdown java.lang.IllegalStateException: Trying to materialize stream after materializer has been shutdown at akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:424) at akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:417) at akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:408) at akka.stream.scaladsl.RunnableGraph.run(Flow.scala:556) at akka.stream.scaladsl.Source.runWith(Source.scala:103) at play.api.libs.streams.StrictAccumulator.run(Accumulator.scala:203) at mockws.FakeWSRequestHolder.executeResult(FakeWSRequestHolder.scala:118) at mockws.FakeWSRequestHolder.execute(FakeWSRequestHolder.scala:103) at mockws.FakeWSRequestHolder.execute(FakeWSRequestHolder.scala:188) at mockws.FakeWSRequestHolder.get(FakeWSRequestHolder.scala:181)

I'm using a web services mock library: https://github.com/leanovate/play-mockws and the error seems to be related to how this library uses and releases the ActorSystem materializer instance during test. For the test configuration related to the actor system I have:

the code inside MockWSHelpers:

trait MockWSHelpers {
  private val actorSystem: ActorSystem = actor.ActorSystem("unit-testing")
  implicit val materializer: ActorMaterializer = ActorMaterializer()(actorSystem)
  val BodyParser: PlayBodyParsers = PlayBodyParsers()
  val Action: DefaultActionBuilder = DefaultActionBuilder(BodyParser.anyContent)

  def shutdownHelpers(): Unit = {
    materializer.shutdown()
    Await.result(actorSystem.terminate(), 3.minutes)
  }

}
object MockWSHelpers extends MockWSHelpers {
  sys addShutdownHook {
    shutdownHelpers()
  }
}

Base Test Class that all tests will inherit from:

abstract class BaseDomainTest extends PlaySpec with MockitoSugar with MockWSHelpers with BeforeAndAfterAll {

  override def afterAll(): Unit = {
    shutdownHelpers()
  }

}

Domain Test classes will extend BaseDomainTest such as:

@RunWith(classOf[JUnitRunner])
class MyTestDomainControllerSpec extends BaseDomainTest {

My impression is that sometimes the scheduled job doesn't finish before the end of the shutdown hook from MockWSHelpers and the exception is thrown, when it does finish before then there are no exceptions.

How to avoid the exception above?

Alternative approach:

One alternative is to just disable the scheduled jobs altogether during tests and just move its internal business logic in a totally separate class. Example:

scheduledTask:

actorSystem.scheduler.schedule(initialDelay = 0.second, interval = intervalSeconds.second) { if (config.isJobEnabled) { myBusinessObject.execute() } }

In this case just testing myBusinessObject.execute() in isolation and not enabling scheduled tasks during tests.

0 Answers
Related