whysoseriousson
whysoseriousson

Reputation: 306

Long running processes inside service invoked from actor

We are using Akka actors in our application. Actors are invoking services and in some cases those services are calling rest API exposed by third party. Now the third party APIs are taking a very long time to respond. Due to this during peak time , the system through put is getting impacted as threads are blocked as they wait for client API to respond.

Sometimes during peak time , because threads are waiting , messages just keep waiting in akka mail box for long time and are picked up, once blocked threads are made available.

I am looking for some solution where in i can improve the throughput of the system and can free up threads so that actor messages can start processing.

I am thinking to change the rest API call from blocking to non blocking call using Future and creating a dedicated actor for such kind of rest API invocations . Actor will periodically check if future is completed and then sends a completion message and then rest of process can continue.This way the number of blocking threads will reduce and they will be available for actor message processing.

Also would like to have separate execution context for actors which are doing blocking operations. As of now we have global execution context.

Need further inputs on this.

Upvotes: 0

Views: 264

Answers (1)

Tim
Tim

Reputation: 27356

Firstly, you are correct that you should not block when processing a message, so you need to start an asynchronous process and return immediately from the message handler. The Actor can then send another message when the process completes.

You don't say what technology you are using for the REST API calls but libraries like Akka HTTP will return a Future when making an HTTP request so you shouldn't need to add your own Future around it. E.g:

def getStatus(): Future[Status] = 
  Http().singleRequest(HttpRequest(uri = "http://mysite/status")).flatMap {
    res =>
      Unmarshal(res).to[Status]
  }

If for some reason you are using a synchronous library, wrap the call in Future(blocking{ ??? }) to notify the execution context that it needs to create a new thread. You don't need a separate execution context unless you need to control the scheduling of threads for this operation.

You also don't need to poll the Future, simply add an onComplete handler that sends an internal message back to your actor which then processes the result of the API call.

Upvotes: 1

Related Questions