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
Related
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 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 {
}
I am new to scala/akka. I need to create a trait and from this trait, to retrieve actors from a context or directly from an actorSystem.
But I don't want this trait to either extends Actor, nor force to be mixed with an Actor.
Is there a way to do that?
Thanks.
Welcome to Akka :-)
You should create a trait with an abstract method, that will be used to retrieve the actor system, for example like this:
trait DoesThings {
def system: ActorSystem
def findActor(name: String) = // do actor selection using system here
}
object Example extends DoesThings {
val system = ActorSystem("example")
val ref = findActor
}
Happy hakking!
You can put an actor system val in the trait.
And with instantiation you will pass used actor system to it.
You could try something like this:
trait ActorLookup{
def actorSelection(path:ActorPath)(implicit fact:ActorRefFactory) = fact.actorSelection(path)
def actorSelection(path:String)(implicit fact:ActorRefFactory) = fact.actorSelection(path)
}
class ActorBasedImpl extends Actor with ActorLookup{
def receive = {
case _ =>
val ref = actorSelection("/foo")
}
}
class NonActorBasedImpl extends ActorLookup{
implicit val system = ActorSystem("foo")
...
val ref = actorSelection("/user/foo")
}
Within an Actor, you already have an implicit ActorRefFactory in scope so no need to define one. If you wanted to use the ActorSystem instead there, you could just pass it explicitly like so:
actorSelection("/user/foo")(context.system)
Outside an Actor, it's more likely you will be using an ActorSystem instead of an ActorContext to perform lookups, so that's why an implicit ActorSystem was defined. But again, you don't have to define it as an implicit and could just use it explicitly if desired.
I am wanting to test one of my akka actors, it uses slick to get the information from the database. In my actor I have this bit of code
CardStationPermissions.retrieveByStationID(stationID).foreach(card => {
I want to know how can I mock that function to change the output instead of relaying on whats in the database?
It's really difficult to mock things that are being called in a static way (in this case, a call on an object as opposed to an instance of a class). When you need to be able to mock and test things like this, I tend to agree with Mustafa's suggestion that creating a trait to represent the relevant methods to mock. A simple example would look as follows:
case class MyObject(id:Long)
trait MyDao{
def getData(input:String):List[MyObject] = ...
}
object MyDao extends MyDao
class MyActor extends Actor{
val myDao:MyDao = MyDao
def receive = {
case param:String => sender ! myDao.getData(param)
}
}
Here you can see that I have a trait to represent my dao methods (only 1 for this example) and then I mix that trait into a scala object as the default instantiation of that trait. When I setup my dao in my actor, I explicitly type it to the trait so that I can substitute a mock impl of that trait later.
So then if I wanted a simple test showing mocking, it could look something like this (via specs2):
class MyActorTest(_system:ActorSystem) extends TestKit(_system)
with Specification with Mockito with ImplicitSender{
def this() = this(ActorSystem("test"))
trait scoping extends Scope{
val mockDao = mock[MyDao]
val actor = TestActorRef(new MyActor{
override val myDao = mockDao
})
}
"A request to get data" should{
"pass the input to the dao and return the result to the sender" in new scoping{
mockDao.getData("foo") returns List(MyObject(1))
actor ! "foo"
expectMsg(List(MyObject(1)))
}
}
}
I'm learning Spray and Akka. And I'm learning it through TypeSafe's templates, and this one is very complex at least:
http://typesafe.com/activator/template/akka-spray-websocket
I now understand the werid structure this template has is to separate routing logic and business logic and it's amazingly done. However, although I know the purpose of this structure, I don't know what's the functionality of this small piece and why is it necessary:
They have a class called MainActors.scala:
trait MainActors {
this: AbstractSystem =>
lazy val find = system.actorOf(Props[FindActor], "find")
lazy val hide = system.actorOf(Props[HideActor], "hide")
}
Then the template concatenates all the routings under a class called ReactiveApi.scala:
trait AbstractSystem {
implicit def system: ActorSystem
}
trait ReactiveApi extends RouteConcatenation with StaticRoute with AbstractSystem {
this: MainActors =>
val rootService = system.actorOf(Props(classOf[RootService], routes))
lazy val routes = logRequest(showReq _) {
new FindService(find).route ~
new HideService(hide).route ~
staticRoute
}
private def showReq(req : HttpRequest) = LogEntry(req.uri, InfoLevel)
}
Actually, my question is simple: what is the purpose of AbstractSystem trait? how is it used and why is it used?
This trait is also passed into actual actor:
class FindService(find : ActorRef)(implicit system : ActorSystem) extends Directives {
lazy val route = ...
}
Also, if it is not entirely inconvenient, what's the functionality of logRequest() and showReq()?
For Spray: why do I have to pass an actor (ActorRef) into FindServce? I don't see any specific methods being invoked from inside.
This is a very simple example of using abstract defs in order to do the cake pattern (very simplified though). The goal is to say "hey, I need this thing", and the implementor must then provide the actor system to you – by implementing the def system. The goal is of course to make this def available to MainActors.
As for the self type reference, you can refer to ktoso/types-of-types#self-type-annotation to find out more about it.