Skip to content
This repository has been archived by the owner on Apr 8, 2020. It is now read-only.

Rewriter/Singleton question #57

Closed
pjan opened this issue Apr 14, 2017 · 2 comments
Closed

Rewriter/Singleton question #57

pjan opened this issue Apr 14, 2017 · 2 comments

Comments

@pjan
Copy link
Contributor

pjan commented Apr 14, 2017

From the documentation / @etorreborre's talk, I was under the impression that when using a singleton/rewriter, it makes sure the specific module only gets initialized once. However, when running the example below (dependencies akka-cluster & grafter), the ActorSystemProvider is being initialized twice.

I'm fairly sure the mistake is probably somewhere on my end, but at the same time am unable to track it down, or deduce from the documentation what I am doing wrong. Any ideas here?

package demo

import akka.actor._
import cats.Eval
import cats.data.Reader
import org.zalando.grafter._
import org.zalando.grafter.GenericReader._
import org.zalando.grafter.macros._
import org.zalando.grafter.syntax.rewriter._

@readers
case class ApplicationConfig(
    akka: AkkaConfig
)

case class AkkaConfig(
    clusterName: String
)

trait DB

object DB {
  implicit def reader: Reader[ApplicationConfig, DB] =
    AkkaDB.reader
}

case class AkkaDB(actorSystemProvider: ActorSystemProvider) extends DB with Start {
  override def start: Eval[StartResult] = StartResult.eval("DB") {}
}

object AkkaDB {
  implicit def reader: Reader[ApplicationConfig, AkkaDB] =
    genericReader
}

trait ActorSystemProvider {
  def system: ActorSystem
}

object ActorSystemProvider {
  implicit def reader[A](implicit akkaConfigReader: Reader[A, AkkaConfig]): Reader[A, ActorSystemProvider] =
    DefaultActorSystemProvider.reader[A]
}

@dependentReader
final case class DefaultActorSystemProvider private (config: AkkaConfig)
    extends ActorSystemProvider
    with Start
    with Stop {

  lazy val systemEval: Eval[ActorSystem] =
    Eval.later(ActorSystem(config.clusterName))

  lazy val system: ActorSystem =
    systemEval.value

  override def start: Eval[StartResult] = {
    StartResult.eval("akka")(system)
  }

  override def stop: Eval[StopResult] = {
    StopResult.eval("akka")(system.terminate())
  }
}

object DefaultActorSystemProvider {
  implicit def reader[A](implicit akkaConfigReader: Reader[A, AkkaConfig]): Reader[A, ActorSystemProvider] =
    akkaConfigReader.map(DefaultActorSystemProvider.apply)
}

@reader[ApplicationConfig]
case class Application(actorSystemProvider: ActorSystemProvider, db: DB)

object Main extends App {

  pureconfig.loadConfig[ApplicationConfig]("app") match {
    case Left(error)  println(error)
    case Right(applicationConfig) 
      val application = GenericReader[ApplicationConfig, Application]
        .run(applicationConfig)
        .singleton[ActorSystemProvider]

      Rewriter
        .start(application)
        .flatMap {
          case results if results.exists(!_.success) 
            println(results)
            Eval.now(())
          case _ 
            Eval.now(())
        }
        .value

  }

}
@pjan
Copy link
Contributor Author

pjan commented Apr 14, 2017

OK, found it myself. It was the final modifier that did it. Closing...

@pjan pjan closed this as completed Apr 14, 2017
@jcranky
Copy link
Contributor

jcranky commented Apr 14, 2017

We are still improving the documentation, but you are right about the final keyword. The fact that finals are not turned into singletons is mentioned here: https://github.com/zalando/grafter/blob/master/doc/singletons.md

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants