Search code examples
lagom

unable to understand execution flow in lagom


I am following this tutorial - https://www.lagomframework.com/documentation/1.3.x/scala/ServiceImplementation.html

I created a logged service

//logged takes a ServerServiceCall as argument (serviceCall) and returns a ServerServiceCall.
  //ServerServiceCall's compose method creates (composes) another ServerServiceCall
  //we are returing the same ServerServiceCall that we received but are logging it using println
  def logged[Request,Response](serviceCall:ServerServiceCall[Request,Response]) = {
    println("inside logged");

    //return new ServerServiceCall after logging request method and uri
    ServerServiceCall.compose({
    requestHeader=>println(s"Received ${requestHeader.method} ${requestHeader.uri}")
    serviceCall
  }
  )}

I used logged as follows:

  override def hello3 = logged(ServerServiceCall
  { (requestHeader,request) =>
    println("inside ssc")
    val incoming:Option[String] = requestHeader.getHeader("user");

    val responseHeader = ResponseHeader.Ok.withHeader("status","authenticated")
    incoming match {
      case Some(s) => Future.successful((responseHeader,("hello3 found "+s)))
      case None => Future.successful((responseHeader,"hello3 didn't find user"))
    }
  })

I expected that inside ssc would be printed first and then print in logged but it was opposite. Shouldn't the arguments passed to the function be evaluated first?

I got this. Why?

inside logged Received POST /hello3 inside ssc


Solution

  • logged is a function that you've written that takes a ServiceCall and decorates it with its own ServiceCall. Later on, Lagom invokes the service call with the request header. You are logging inside logged at the point that the service call is decorated, before it has been returned to Lagom, and so before it has been invoked, that's why it gets invoked first. This might explain it:

    def logged[Request, Response](serviceCall:ServerServiceCall[Request, Response]) = {
      println("3. inside logged method, composing the service call")
      val composed = ServerServiceCall.compose { requestHeader=>
        println("6. now Lagom has invoked the logged service call, returning the actual service call that is wrapped")
        serviceCall
      }
    
      println("4. Returning the composed service call")
      composed
    }
    
    override def hello3 = {
      println("1. create the service call")
      val actualServiceCall: ServerServiceCall[Request, Response] = ServerServiceCall { (requestHeader, request) =>
        println("7. and now the actual service call has been invoked")
        val incoming:Option[String] = requestHeader.getHeader("user");
    
        val responseHeader = ResponseHeader.Ok.withHeader("status","authenticated")
        incoming match {
          case Some(s) => Future.successful((responseHeader,("hello3 found "+s)))
          case None => Future.successful((responseHeader,"hello3 didn't find user"))
        }
      }
    
      println("2. wrap it in the logged service call")
      val loggedServiceCall = logged(actualServiceCall)
    
      println("5. return the composed service call to Lagom")
      loggedServiceCall
    }
    

    The important thing to remember is that the invocation of the hello3 method is not the invocation of the service call, hello3 merely returns a ServiceCall that Lagom will use to invoke it.