简体   繁体   English

Lagom服务在收到源时未响应

[英]Lagom service does not responding when it receives Source

I'm playing with Lagom and created service receiving Source as input and returning case class object: 我正在玩Lagom,并创建了接收Source作为输入并返回case类对象的服务:

import akka.NotUsed
import akka.stream.scaladsl.Source
import com.lightbend.lagom.scaladsl.api.{Service, ServiceCall}
import play.api.libs.json.{Format, Json}

trait TestService extends Service {
  def test(): ServiceCall[Source[String, NotUsed], ResultData]

  override final def descriptor = {
    import Service._
    named("DocsStore")
      .withCalls(
        call(test())
      )
  }
}


case class ResultData(uploadId: String, length: Long)

object ResultData {
  implicit val format: Format[ResultData] = Json.format[ResultData]
}

Service implementation is: 服务实现是:

class TestServiceImpl()(
  implicit val materializer: Materializer,
  implicit val ec: ExecutionContext
) extends TestService {
  val logger = Logger(getClass.getName)

  override def test(): ServiceCall[Source[String, NotUsed], ResultData] = ServiceCall{ source=>
    source.runForeach(s=>logger.info(s"String $s")).map(_=>ResultData("TestResult", 12))
  }
}

When I call this service from Play application's controller: 当我从Play应用程序的控制器调用此服务时:

  def test = Action.async { req=>
    testService.test().invoke(Source("A"::"B"::"C"::Nil)).map(rd=>Ok(Json.toJson(rd)))
  }

"runForeach" on service side successfully prints A, B, C but service itself does not return any result value (ResultData("TestResult", 12) is expected) causing Play application throw exception: 服务端的“ runForeach”成功打印了A,B,C,但服务本身未返回任何结果值(预期为ResultData(“ TestResult”,12)),导致Play应用程序抛出异常:

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[DeserializationException: No content to map due to end-of-input
 at [Source: akka.util.ByteIterator$ByteArrayIterator$$anon$1@309c63af; line: 1, column: 0]]]
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:293)
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:220)
    at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
    at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
    at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:100)
    at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:100)
    at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:99)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:346)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:345)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)

How this could be fixed? 如何解决?

This happens because Lagom interprets the completion of the stream as a signal to close the connection. 之所以会发生这种情况,是因为Lagom将流的完成解释为关闭连接的信号。 The connection is closed before the response can be sent. 在发送响应之前,连接已关闭。

This has been raised as an issue in GitHub: https://github.com/lagom/lagom/issues/814 这已在GitHub中作为一个问题提出: https : //github.com/lagom/lagom/issues/814

A possible workaround is to leave the stream open until the response is received, as demonstrated in the documentation on testing streaming services : 一种可能的解决方法是将流保持打开状态,直到收到响应为止,如有关测试流服务的文档中所示:

// Use a source that never terminates (concat Source.maybe) so we
// don't close the upstream, which would close the downstream
val input = Source("A"::"B"::"C"::Nil).concat(Source.maybe)

However, if using this strategy, the service implementation will also need to be changed, as the implementation in the question above only sends the response when the stream is completed. 但是,如果使用此策略,则还需要更改服务实现,因为上面问题中的实现仅在流完成时发送响应。 Instead, you'll need to design into your protocol an explicit completion message that signals to the service to send the response. 相反,您需要在协议中设计一条显式的完成消息,该消息会向服务发出信号以发送响应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM