Service not found. Hint: Maybe it was not registered?

akka
dependency-injection
scala

(dheeraj) #1

I’m consuming messages from external Kafka like this and feeding those messages to one of the actors let’s suppose MyActor

This actor is having a constructor dependency of one another microservice let’s say ServiceApiToBeCallFromAnActor

Now before this actor start processing any message I wanted to invoke one of the rest endpoints from ServiceApiToBeCallFromAnActor so I override actors preStart life cycle event.

Now when I tried to invoke rest endpoint inside preStart, sometime it works and sometimes it doesn’t work and gives following warning

[warn] com.lightbend.lagom.internal.scaladsl.registry.ServiceRegistryServiceLocator [] - Service name=[service-to-be-call-from-actor-api] was not found. Hint: Maybe it was not registered?

Some of the source code is like


//Inside application loader, dependecies are as follows

  lazy val serviceApiToBeCallFromAnActor = serviceClient.implement[ServiceApiToBeCallFromAnActor]
  lazy val myActor: MyActor = wire[MyActor]
  lazy val myActorRef = actorSystem.actorOf(Props(myActor), name = "MyActor) 
  wire[Engine]

//Engine consuming messages is as follows

class Engine (myActor: ActorRef) (implicit executionContext: ExecutionContext) {
  engineService
    .messages()
    .subscribe
    .atLeastOnce(Flow.fromFunction(message => {
      myActor ! message
      Done
    }))
}

//MyActor

class MyActor(serviceApiToBeCallFromAnActor: ServiceApiToBeCallFromAnActor)
(implicit executionContext: ExecutionContext) extends Actor with ActorLogging {
  
  override def preStart() = {
    serviceToBeCallFromActor
      .requestSomething
      .invoke()
      .map(res => SetResponse(res)) pipeTo self //This is the line

  override def receive: Receive = {
    case someOtherCases => {}
    case SetResponse(res) => {
      println("This statement is not get printed always....") //And this one
    }
  }
}

I read this article and thanks @ignasi35 for your explanation I think in my case service isn’t registered yet and before that, i am trying to make an API call.

But guys what should I do where should I make that API call? Is there any callback event for service registration so that on which I can raise an API call.

@TimMoore, @renato, @ignasi35 Please help me.

Regards,
Dheeraj


(Alan Klikic) #2

@dheeraj you need to handle service query failures (service not found, connection failure,…) in your actor.

You have two options:

  1. handling failure in actor
  2. using backoff + cluster singleton

#1) actor message flow is controling service query lifecycle
Service query result should be piped (Use the pipe pattern to actor.
Actor should have two behaviors (see - not-ready and ready.
Initial state is not-ready. In preStart you query the service and pipe result to actor. In case of failure you schedule, with short delay, a next query.
In case of success you would change behavior to ready.
Only ready behaviour accepts consumed messages from kafka.

#2) wrap your actor in backoff and cluster singleton.
In case of service query failure actor should stop and Backoff will restart the actor and query will be repeated.
Check Akka supervision for referenced implementation.
When using backoff you do not have access to your actor ActorRef to send consumed messages so you would need cluster singleton (cluster singleton client) for that.
Check Cluster singleton
Here is an example but in java.
I would not sugget this option because of scalability issues.

Note: When consuming message and sending it to an actor, I suggest you implement ask rather then tell so you can get a back-pressure and if actor is not ready messges can be resent (if you require at least once semantic).

Hope this helps.


(dheeraj) #3

thanks @aklikic

Actually, when the call happens and if in case it gets fail it doesn’t respond with anything.
I just got the warning message on the console and that’s it so I can not pipe it.

For now, I have implemented the workaround as follow:
In preStart i am scheduling pre-initialization message with a delay and in on receive, I am making that API call so all working good for now.

context.system.scheduler.scheduleOnce(delay seconds, self, PreInitialization)

I am not sure why I didn’t get any exception if service is not registered yet.
Why swallow an exception with a warning message?

@aklikic thanks again.

Regards,
Dheeraj


(Alan Klikic) #4

@dheeraj did you try printing result in map ?