John Doe
John Doe

Reputation: 281

How to avoid saving state in Scala class?

I am currently writing a client application in Scala which makes HTTP requests to an API. In this client application I have implemented a service connector which encapsulates all API related logic. Before making API calls, I want to authenticate the user, but I want to abstract this process. Which means that my actor would only call the service connector to initiate the API call, something like that:

class MessageProcessor(credentials: Credentials) extends Actor with ActorLogging {

  implicit val ec = context.dispatcher

  override def receive: Receive = {
    case sendMsg: SendMessage =>
      log.info(s"Sending message ${sendMsg.body}.")
      sendMessage(sendMsg)
  }

  def sendMessage(msg: SendMessage) = {
    ServiceConnector.sendMessage(credentials, msg).map { result =>
      // My result
    }

  }

}

object MessageProcessor {
  def props(credentials: Credentials) = Props(classOf[MessageProcessor], credentials)
}

In my service connector, I want to somehow save "the Scala way" the JWT token and if I am not yet authenticated, send an authentication request before making the actual API call.

How can I code such a service in an immutable manner with Futures in mind?

I thought about creating additional actors and just sending messages around with the token, but is this really necessary?

Upvotes: 0

Views: 391

Answers (2)

Actors Are Designed For State

This seems like a false exercise. The entire point of Actors is that they can warehouse state. From the documentation specifically on state:

The good news is that Akka actors conceptually each have their own light-weight thread, which is completely shielded from the rest of the system. This means that instead of having to synchronize access using locks you can just write your actor code without worrying about concurrency at all.

Therefore, "the scala way" is just to keep it in a variable within Actors.

One of the reasons to use Actors instead of Futures is so you can maintain state. Why choose Actors and then dismiss one of their primary advantages???

Your question is the equivalent of "how do I use HashMap without doing any hashing (in a scala way)?"

Upvotes: 0

matfax
matfax

Reputation: 685

You need multiple Akka states to do it the proper "Scala way". I'm not completely sure how your API works, but the following example shows a basic approach. In its first state, it authenticates before sending the message. Once the authentication is confirmed, it sends the message. All following messages are immediately sent. If the authentication is lost somehow, you can also add a logout or timeout case that switches back to the first receive state.

class MessageProcessor(credentials: Credentials) extends Actor with ActorLogging {

  implicit val ec = context.dispatcher

  override def receive: Receive = {
    case sendMsg: SendMessage =>
      log.info(s"Authenticating...")
      sender ! NotAuthenticated(credentials) // or authenticate somehow
      context become waitingAuthentication(sendMsg)
  }

  def waitingAuthentication(sendMsg: SendMessage): Receive = {
    case _: AuthenticationConfirmation =>
      log.info(s"Sending message ${sendMsg.body}.")
      sendMessage(sendMsg)
      context become authenticated
  }

  def authenticated: Receive = {
    case sendMsg: SendMessage =>
      log.info(s"Sending message ${sendMsg.body}.")
      sendMessage(sendMsg)
  }

}

It's just an example and doesn't consider all cases (e.g., a SendMessage during waitingAuthentication, therefore you would need a queue of SendMessages). If multiple actors need to know the authentication state or the credentials, you need to broadcast to them if you don't want a bottleneck actor that handles and verifies all messages. In that case, all of them would also need multiple authentication states as described above.

Upvotes: 2

Related Questions