使用喷雾罐进行喷涂 - 交给演员只在我的应用程序中有效

时间:2015-08-17 18:42:05

标签: scala spray

抱歉,这有点长,因为我需要包含各种文件。

问题

我不确定我的设置[使用喷雾1.3.3]发生了什么。我正在尝试使用chunked请求进行文件上传,这些请求似乎按预期工作一次或两次,但由于某些原因,大多数时候actor在块处理程序的初始注册完成后从未接收到块。它只是消失在遗忘中,我的请求和日志只是一直在等待。当我运行调试器时,它完成了50次中的2次。然而,即使使用调试器,它也不会起作用。

基于与DemoService和FileUploadHandler相关的各种示例和讨论,我使用spray-can来检查接收到的HttpMessage的块,并在那时产生一个单独的路由。我使用curl with chunked encoding来测试我的输出。

请帮忙!我花了太多时间试图获得与我的用例工作路由混合的分块请求。

代码

这是我的代码:

TestApp.scala

object TestApp extends App with GlobalConfig {

  implicit val system = ActorSystem("TestApp")
  implicit val ec = system.dispatcher

  val healthActor = system.actorOf(Props[HealthStateActor])

  val routes = new HealthcheckController(healthActor).route ~
               new ResourceController().route

  val requestRouter = system.actorOf(Props(new HttpRequestCustomHandler(routes)))

  IO(Http) ! Http.Bind(requestRouter, "0.0.0.0", HttpBindPort)
}

FileUploadActor.scala

class FileUploadActor(client: ActorRef, requestMetadata: RequestMetadata, request: HttpRequest, ctx: RequestContext)
  extends Actor with ActorLogging with GlobalConfig {

  import request._

  var bytesWritten = 0L
  var bytes: Array[Byte] = "".getBytes

 // client ! CommandWrapper(SetRequestTimeout(Duration.Inf)) // cancel timeout

  def receive = {
    case c: MessageChunk =>
      log.info(s"Got ${c.data.length} bytes of chunked request $method $uri")

      bytes ++= c.data.toByteArray
      bytesWritten += c.data.length

    case e: ChunkedMessageEnd =>
      log.info(s"Got end of chunked request $method $uri. Writing $bytesWritten bytes for upload: $requestMetadata")

      Try(saveFile(requestMetadata)) match {
        case Success(_) => ctx.complete(HttpResponse(StatusCodes.Created, entity = "success"))
        case Failure(f) => f.printStackTrace(); ctx.complete(HttpResponse(StatusCodes.InternalServerError, entity = "failure"))
      }

  //    client ! CommandWrapper(SetRequestTimeout(UploadRequestTimeout.seconds)) // reset timeout to original value
      context.stop(self)
  }
}

FileUploadService.scala

RegisterChunkHandler消息是我看到调试器在断点处停止的最后一步,以及日志安静的位置。当它工作时,我可以看到FileUploadActor收到MessageChunk消息。

trait FileUploadService extends Directives {
  this: Actor with ActorLogging with GlobalConfig =>

  def chunkedRoute() = {

    path(resourceAPI / "upload" / "resource" / Segment) { resourceId =>
      put {
        detach() {

            ctx => {
              val request = ctx.request
              val client = sender()

              val handler = context.actorOf(Props(new FileUploadActor(client,
                RequestMetadata(....),
                request, ctx)))

              sender ! RegisterChunkHandler(handler)
            }
        }
      }
    }
  }
}

HttpRequestCustomHandler.scala

class HttpRequestCustomHandler(routes: Route, resourceProviderRef: ResourceProvider)
  extends HttpServiceActor
  with FileUploadService
  with ActorLogging
  with GlobalConfig {

  val normal = routes
  val chunked = chunkedRoute()

  def resourceProvider = resourceProviderRef

  val customReceive: Receive = {
    // clients get connected to self (singleton handler)
    case _: Http.Connected => sender ! Http.Register(self)

    case r: HttpRequest =>
      normal(RequestContext(r, sender(), r.uri.path).withDefaultSender(sender()))

    case s@ChunkedRequestStart(HttpRequest(PUT, path, _, _, _)) =>
      chunked(RequestContext(s.request, sender(), s.request.uri.path).withDefaultSender(sender()))
  }

  override def receive: Receive = customReceive
}

HttpRequestHandler.scala

abstract class HttpRequestHandler(routes: Route) extends HttpServiceActor{

  override def receive: Receive = runRoute(routes)
}

application.conf:

spray.can.server {
  request-timeout = 20 s

  pipelining-limit = disabled
  reaping-cycle = infinite
  stats-support = off
  request-chunk-aggregation-limit = 0

  parsing.max-content-length = 100000000
  parsing.incoming-auto-chunking-threshold-size = 15000000
  chunkless-streaming = on

  verbose-error-messages = on
  verbose-error-logging = on
}

卷曲成功:

    curl -vvv -X PUT -H "Content-Type: multipart/form-data" -d    
'@/Users/abc/Documents/test.json' 
'http://localhost:8180/upload/resource/02521081'
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8100 (#0)
> PUT /upload/resource/02521081 HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:8100
> Accept: */*
> Content-Type: multipart/form-data
> Content-Length: 82129103
> Expect: 100-continue
> 
< HTTP/1.1 100 Continue
< HTTP/1.1 201 Created
* Server spray-can/1.3.3 is not blacklisted
< Server: spray-can/1.3.3
< Date: Mon, 17 Aug 2015 07:45:58 GMT
< Content-Type: text/plain; charset=UTF-8
< Content-Length: 7
< 
* Connection #0 to host localhost left intact
success

卷曲失败(永远等待):

* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8100 (#0)
> PUT /upload/resource/02521081 HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:8100
> Accept: */*
> Transfer-Encoding: chunked
> Content-Type: multipart/form-data
> Expect: 100-continue
> 
< HTTP/1.1 100 Continue

^C

失败(永远等待):

resource 2015-08-17 01:33:09.374  [Resource] INFO  akka.event.slf4j.Slf4jLogger   - Slf4jLogger started
resource 2015-08-17 01:33:09.396 08:33:09.382UTC [Resource] DEBUG akka.event.EventStream main EventStream(akka://resource) - logger log1-Slf4jLogger started
resource 2015-08-17 01:33:09.404 08:33:09.383UTC [Resource] DEBUG akka.event.EventStream main EventStream(akka://resource) - Default Loggers started
resource 2015-08-17 01:33:10.160 08:33:10.159UTC [Resource] INFO  spray.can.server.HttpListener Resource-akka.actor.default-dispatcher-4 akka://resource/user/IO-HTTP/listener-0 - Bound to /0.0.0.0:8100

成功(为清晰起见编辑了日志):

resource 2015-08-17 00:42:12.283  [Resource] INFO  akka.event.slf4j.Slf4jLogger   - Slf4jLogger started
resource 2015-08-17 00:42:12.295 07:42:12.290UTC [Resource] DEBUG akka.event.EventStream main EventStream(akka://resource) - logger log1-Slf4jLogger started
resource 2015-08-17 00:42:12.308 07:42:12.291UTC [Resource] DEBUG akka.event.EventStream main EventStream(akka://resource) - Default Loggers started
resource 2015-08-17 00:42:13.007 07:42:13.005UTC [Resource] INFO  spray.can.server.HttpListener Resource-akka.actor.default-dispatcher-4 akka://resource/user/IO-HTTP/listener-0 - Bound to /0.0.0.0:8100
resource 2015-08-17 00:43:47.615 07:43:47.529UTC [Resource] DEBUG c.l.resource.actor.FileUploadActor Resource-akka.actor.default-dispatcher-7 akka://resource/user/$b/$b - Got 131072 bytes of chunked request PUT http://localhost:8100/resourcesvc/0.2/api/upload/resource/02521081-20e5-483a-929f-712a9e11d117/content/5adfb5-561d-4577-b6ad-c6f42eef98
resource 2015-08-17 00:43:49.220 07:43:49.204UTC [Resource] DEBUG c.l.resource.actor.FileUploadActor Resource-akka.actor.default-dispatcher-7 akka://resource/user/$b/$b - Got 131072 bytes of chunked request PUT http://localhost:8100/resourcesvc/0.2/api/upload/resource/02521081-20e5-483a-929f-712a9e11d117/content/5adfb5-561d-4577-b6ad-c6f42eef98
.
.
.
resource 2015-08-17 00:44:05.605 07:44:05.605UTC [Resource] DEBUG c.l.resource.actor.FileUploadActor Resource-akka.actor.default-dispatcher-7 akka://resource/user/$b/$b - Got 45263 bytes of chunked request PUT http://localhost:8100/resourcesvc/0.2/api/upload/resource/02521081-20e5-483a-929f-712a9e11d117/content/5adfb5-561d-4577-b6ad-c6f42eef98
resource 2015-08-17 00:44:05.633 07:44:05.633UTC [Resource] INFO  c.l.resource.actor.FileUploadActor Resource-akka.actor.default-dispatcher-7 akka://resource/user/$b/$b - Got end of chunked request PUT http://localhost:8100/resourcesvc/0.2/api/upload/resource/02521081-20e5-483a-929f-712a9e11d117/content/5adfb5-561d-4577-b6ad-c6f42eef98. Writing 82129103 bytes for upload: RequestMetadata(...,multipart/form-data)
resource 2015-08-17 00:44:05.634 07:44:05.633UTC [Resource] DEBUG c.l.resource.actor.FileUploadActor Resource-akka.actor.default-dispatcher-7 akka://resource/user/$b/$b - actor is akka://resource/user/$b/$b, sender is Actor[akka://resource/temp/$a], client is Actor[akka://resource/temp/$a]
resource 2015-08-17 00:45:58.445  [Resource] DEBUG com.abc.resource.io.FileClient$   - UploadResult@109a69fb
resource 2015-08-17 00:45:58.445  [Resource] DEBUG com.abc.resource.io.FileClient$   - upload is done: true

如果您发现任何奇怪的事,请告诉我。演员通常会像这样消失的原因是什么?在此先感谢您的帮助!

更新

我添加了进一步的日志记录,并且看到from和to actor显然都变成了deadLetters,尽管在上面的日志行中显然不是这样。这是消息&#39; RegisterChunkHandler&#39;发送到FileUploadService.scala中的发件人。

sender ! RegisterChunkHandler(handler)

相关日志:

resource 2015 - 0 8 - 17 21: 14: 32.173 20: 14: 32.173 UTC[Resource] DEBUG c.l.a.io.HttpRequestCustomHandler Resource - akka.actor.default - dispatcher - 3 akka :// Resource / user / httpcustomactor - sender is Actor[akka :// Resource / temp / $a]
resource 2015 - 0 8 - 17 21: 14: 32.175 20: 14: 32.175 UTC[Resource] INFO  akka.actor.DeadLetterActorRef A4Resource-akka.actor.default-dispatcher-6 akka://A4Resource/deadLetters - Message [spray.can.Http$RegisterChunkHandler] from Actor[akka://A4Resource/user/httpcustomactor#-1286373908] to Actor[akka://A4Resource/deadLetters] was not delivered. [2] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
resource 2015 - 0 8 - 17 21: 14: 32.176 20: 14: 32.176 UTC[Resource] DEBUG c.l.resource.actor.FileUploadActor Resource - akka.actor.default - dispatcher - 7 akka :// Resource / user / httpcustomactor / $a - pre - start

知道如何避免这种情况吗?

0 个答案:

没有答案