implicit Akka system in Scala trait - scala

How can I make my ActorSystem available in ServiceA and ServiceB, this is the code im trying to get get working. It compile but i get a null pointer exception for the implicit system in Tcp.
Why do I get a nullpointer exception and what can i change to get my
system into my trait services? Why does it compile?
trait ServiceA {
implicit val system: ActorSystem
}
trait ServiceB {
implicit val system: ActorSystem
Tcp().outgo... // Code compile but i get nullpointer exception
}
object Main extends App with ServiceA with ServiceB {
override implicit val system: ActorSystem = ActorSystem("MySys")
}

Constructors of SystemA and SystemB (which uses system) are executed before constructor of Main which includes initialization of system. Use implicit lazy val system = ... in Main (it is allowed to implement an abstract val in this way) and this problem should be fixed.

As an addition to answer
by #alexei_romanov .
What do you want to achieve by placing Tcp... call in a trait body without assigning it to val or def? It is now just an action which is executed at some moment during initialization of Main. It can leat to undefined behavior since it is an action on not yet initialized object.

This is caused by the trait initialization order, and it is indeed unfortunate that the type system cannot defend against this.
One option to resolve this is to put the ActorSystem initialization into its own trait and make sure that one gets mixed in first, so:
trait ServiceA {
implicit val system: ActorSystem
}
trait ServiceB {
implicit val system: ActorSystem
Tcp().outgo... // Code compile but i get nullpointer exception
}
trait ActorSystemInitialization {
val system: ActorSystem = ActorSystem("MySys")
}
object Main extends App with ActorSystemInitialization with ServiceA with ServiceB {
}

Related

How can I resolve conflicting actor systems while testing akka-http and akka actors at the same spec file?

I have a Route defined using akka-http that uses an actor inside to send messages.
My route looks like this:
path("entity") {
post {
entity(as[Enrtity]) {
entity =>
val result: Future[Message] = mainActor.ask {
ref: akka.actor.typed.ActorRef[Message] =>
Message(
entity = entity,
replyRef = ref
)
}
complete("OK")
}
}
}
My test spec:
class APITest
extends ScalaTestWithActorTestKit(ManualTime.config)
with ScalatestRouteTest
with AnyWordSpecLike {
val manualTime: ManualTime = ManualTime()
// my tests here ...
}
Compiling the test fails since there are conflicting actor systems:
class APITest inherits conflicting members:
[error] implicit def system: akka.actor.typed.ActorSystem[Nothing] (defined in class ActorTestKitBase) and
[error] implicit val system: akka.actor.ActorSystem (defined in trait RouteTest)
Overriding the actor system doesn't help either since the inherited actor systems are of both typed and untyped ones.
How can I resolve this easily?
Update:
This is related to conflicting inherited members with different types, but we might be able to solve what I want to achieve in this context differently.
I spent a little time here while moving over to typed. For anyone still looking, there's a nice hint at https://developer.lightbend.com/guides/akka-http-quickstart-scala/testing-routes.html
// the Akka HTTP route testkit does not yet support a typed actor system (https://github.com/akka/akka-http/issues/2036)
// so we have to adapt for now
lazy val testKit = ActorTestKit()
implicit def typedSystem = testKit.system
override def createActorSystem(): akka.actor.ActorSystem =
testKit.system.classicSystem
Looking at the first comment at https://github.com/akka/akka-http/issues/2036 it notes
Perhaps just a docs addition to show that you don't need to use the ActorTestKit from Akka Typed and can just use TestProbes e.g. https://gist.github.com/chbatey/964b80adc2cd124fa4bf4624927b5be0
or val probe = TestProbe[Ping]() > val probe = testKit.createTestProbe[Ping]()

How can I fix the missing implicit value for parameter ta: TildeArrow in a test spec

I'm working on a simple test spec using spray and I can't get it to compile correctly, don't know if I'm doing anything wrong. My version of scala is 2.9.3 and spray 1.0.1 (Updating either of them is not a suitable option). Here's my test spec's code:
import org.specs2.mutable.Specification
import spray.testkit.Specs2RouteTest
import spray.http._
import akka.util.Duration
import java.util.concurrent.TimeUnit
import service.MyProxy
abstract class MyTestSpec extends Specification with Specs2RouteTest with MyProxy{
val duration = Duration(30, TimeUnit.SECONDS)
implicit val routeTestTimeout = RouteTestTimeout(duration)
"MyProxy" should {
"return a json for GET requests to the /api/getclass/classCode path for a regular request" in {
Get("/api/getclass/123/") ~> myRoutes~> check {
responseAs[String] must contain("classCode")
contentType === ContentTypes.`application/json`
}
}
} // end should...
} //end class
I'm getting this error when I run the test.
[error] C:\Users\Desktop\Project\MyTestSpec.scala:23: could not find implicit value for parameter ta: MyProxySpec.this.TildeArrow[spray.routing.RequestContext,Unit]
[error] Get("/api/getclass/123/") ~> myRoutes~> check {
[error] ^
[error] one error found
[error] (test:compile) Compilation failed
I've tried different solutions seen on another questions and nothing seems to work so far.
Spray.io: Can't compile test spec
how to make scalatest work with spraytestkit and HttpServiceActor
Basic Spray-Testkit usage to test a route does not work
https://groups.google.com/forum/#!topic/spray-user/H5hkXuDGWYQ
https://groups.google.com/forum/#!topic/spray-user/zFUJSVBPM5c
NOTE: Just for the record, I'm not using scalatest or scalacheck on this. Is purely a [spray] route test.And MyProxy extends Actor
I just struggled with this problem. To figure it out, I waded through the Akka HTTP codebase, which is a jungle of implicits.
My problem seemed to be that without the right secondary implicit in place, the correct TildeArrow instance wasn't being found. If you look at the code, the TildeArrow instance, which is required in the error message, is defined as an implicit def injectIntoRoute in the companion object and it requires a whole host of other implicits.
I suggest writing out your code without any of the implicit sugar. This should better help the compiler give you a proper error message:
"MyProxy" should {
"return a json for GET requests to the /api/getclass/classCode path for a regular request" in {
val request = Get("/api/getclass/123/")
val requestWithRoutes = request.~>(myRoutes)(TildeArrow.injectIntoRoute)
requestWithRoutes.~>(check {
responseAs[String] must contain("classCode")
contentType === ContentTypes.`application/json`
})
}
}
I think the reason is that since there's no concrete instance of the implicit available, the compiler is trying to satisfy the implicit resolution with the abstract class TildeArrow, and the completely unspecified abstract type, ta.Out, doesn't have a ~> defined.
In my specific case, I was missing an implicit ExecutionContextExecutor, whatever that means.
UPDATE
Actually, I looked into it further and the problem was that I had an implicit def ec: ExecutionContextExecutor declared in my route trait, but trait RouteTest defines its name as executor, and so when I defined my own to fulfill the missing implicit, I ended up with two of the same implicit.
It's a cute API, but the implicit magic is way out of control, IMO, especially given how cryptic the error messages tend to be.
The ScalatestRouteTest already provides an implicit ActorySystem. Remove the "implicit" modifier from your actorRefFactory method and the test should get executed.
Spray.io: Can't compile test spec
for akka http:
in my case which refer to akka-http-microservice
the implicit modifier of executionContext and also need to be removed
and should reorder the trait like this : class ServiceSpec extends FlatSpec with Matchers with Service with ScalatestRouteTest
In my case, the not found implicit error appeared when in my TestCase I also imported import monix.execution.Scheduler.Implicits.global (which is probably having some sort of ExecutionContext).
I fixed it adding the monix scheduler import just in the method where I needed it, not on the top imports.
I can reproduce the precise same error message with Scala 2.10 if myRoutes is not actually a route but a Directive[HNil].
I am therefore guessing that in your unshown service.MyProxy class your route does not complete.
ie
trait MyProxy extends HttpService {
val myRoutes = path("foo")
}
Gives this error
trait MyProxy extends HttpService {
val myRoutes = path("foo") {
complete(StatusCodes.Accepted)
}
}
Does not.
To expand a bit on previous answers given, there are some implicits which shouldn't be declared by any other Trait or class that is extends by your Test Class :
the ActorSystem
the ExecutionContext
the DefaultHostInfo (package akka.http.scaladsl.testkit)
the ActorMaterializer
if any of these is declared elsewhere than in ScalatestRouteTest, you'll have the following error thrown :
could not find implicit value for parameter ...TildeArrow[RequestContext, SomethingHereOther]
your build.sbt should have dependencies for akka-stream test along with akka test.
then it should get the whatever dependencies.
refer to this doc:-
scala route test doc

Consuming implicit from consuming class

I'm looking for the best syntax for having contained classes pick up the implicits exposed by their containing classes?
The scenario I have has two dependencies abstracted for testing: The creation of the application's actorsystem, and a webclient that happens to require the actorsystem as well:
trait Core {
implicit def system: ActorSystem
}
trait WebClient {
implicit def system: ActorSystem
}
trait Api extends WebClient {
...
}
trait Server extends Core {
def api: Api
val service = system.actorOf(Props(new Service(api)))
}
Now, i create a new App which provides the actorsystem and api, but the Api needs an implicit actorsystem, and the only way I've figured out is to manually provide it like this:
object ServerApp extends App with Core {
implicit val system = ActorSystem("foo")
val api = new Api {
override implicit def system = implicitly[ActorSystem]
}
}
Is there a better syntax for having WebClient pick up the implicit from Core? I can't have it extend Core, since it is contained by the Core implementation and required as a dependency for something else that is contained there. But override implict def system = implicitly[ActorSystem] seems rather hamfisted for something that should be, er, implicit
You're shadowing the implicit value since they have the same name.
You might consider
class Api()(implicit val system: ActorSystem)
and
val api = new Api

How to mix in traits with implicit vals of the same name but different types?

I have traits from two third party libraries that I'm trying to mix in to my own trait. They both define implicit vals named log.
However, they are of different types - one is an SLF4J Logger, the other is a Spray LoggingContext (which is really an Akka LoggingAdapter). In fact the second trait is from Spray, it's an HttpServer. (Not the most recent version you can find on Github which no longer has that val).
So, here's the code (library one renamed because it's proprietary, the Spray code snipped to show just relevant part):
object LibraryOneShim {
trait LibraryOne {
implicit val log: org.slf4j.Logger = ...
}
}
// https://github.com/spray/spray/blob/a996a5b6bdd830e613583fed86e87bf049fdb8c0/spray-routing/src/main/scala/spray/routing/HttpService.scala
trait HttpService extends Directives {
val log = LoggingContext.fromActorRefFactory // this is a LoggingContext/LoggingAdapter
}
trait MyTrait extends HttpService with LibraryOne {
val myRoute = ...
}
class MyActor extends Actor with MyTrait {
def receive = runRoute(myRoute)
}
This won't compile. The compiler complains:
error: overriding lazy value log in trait HttpService of type
java.lang.Object with spray.util.LoggingContext; lazy value log in
trait LibraryOne$class of type org.slf4j.Logger needs `override'
modifier trait DemoService extends HttpService with LibraryOne {
Is there any way I can mix in these two traits together?
As far as I can tell the only way is to create a CombinedLogger
class CombinedLogger(l1:Logger, l2:LoggingAdapter) extends Logger with LoggingAdapter {
// proxy methods to the correct logger
}
If both loggers were declared as def you could use it like this:
override def log = new CombinedLogger(super[LibraryOne].log, super[HttpService].log)
In this case it's tricky because they are defined as val which tell the Scala compiler they are a single value that will not change. And because of that it will not allow you to call super.log. So you would need to copy the logic of the overridden traits.
The other tricky part in this case is that you would need to proxy 50+ methods in the CombinedLogger.

Akka actor construction in Play! framework

I am playing with the Play! framework and I wanted to create a factory called Services which will create new actors. I have this so far
class UserRegistration extends Actor {
def receive = {
case "foo" => "bar"
}
}
object UserRegistration {
val path: String = "user/registration"
}
object Services {
val system = ActorSystem("Services")
def apply[A<:Actor]: ActorRef = system.actorOf(Props[A], A.path)
}
And I wanted to create and pass messages to actors like this:
Services[UserRegistration] ? "hello"
but I get errors of the type could not find implicit value for evidence parameter of type ClassManifest[A]. Can anyone please tell me what am I doing wrong here? And if this is a valid construction in general (a best practice). I am pretty new in Scala and still learning stuff.
Thanks!
senia's answer works too, but if you want to specify a common path for each type of actor, you need a second implicit parameter(the first being the ClassManifest so that you can specify a path for each type of actor. Keep in mind that actor names have to be unique though, so you have to add something to that path.
First you define a class that holds the Path:
case class Path(value:String)
Then you define an implicit value in the companion object of your actor class:
object SomeActor {
implicit val path = Path("SomeActor")
}
Finally you modify the apply method to take an implicit class manifest as well as an implicit path.
def apply[A<:Actor](implicit cm:ClassManifest[A], path:Path[A]): ActorRef =
system.actorOf(Props[A], path.value + someIndex)
Method apply of object Props implicitly takes parameter of type ClassManifest[T].
apply [T <: Actor] (implicit arg0: ClassManifest[T])
You have to add such parameter into your method:
def apply[A<:Actor : ClassManifest]: ActorRef = system.actorOf(Props[A])