1
votes

I'm trying to send received http request's content to akka nodes to handle. I have tried below content types and akka received message correctly. However, when I am sending AnyContentAsMultipartFormData, akka won't accept it.

I'm wondering why.

Below is my log for http request received by play framework:

2015-08-29 15:05:08.952 [INFO] [application] in application-akka.actor.default-dispatcher-5 
body is AnyContentAsFormUrlEncoded(Map(test -> ArrayBuffer(test)))
2015-08-29 15:06:31.867 [INFO] [application] in application-akka.actor.default-dispatcher-18 
body is AnyContentAsText({})
2015-08-29 15:08:23.787 [INFO] [application] in application-akka.actor.default-dispatcher-18 
body is AnyContentAsJson({})
2015-08-29 15:09:07.290 [INFO] [application] in application-akka.actor.default-dispatcher-6 
body is AnyContentAsMultipartFormData(MultipartFormData(Map(abc -> List(2), test -> List(1)),List(),List(),List()))

And akka log is as below:

2015-08-29 15:05:09.146 [INFO] [actors.PlatService] in application-akka.actor.default-dispatcher-2 
body is AnyContentAsFormUrlEncoded(Map(test -> ArrayBuffer(test)))

2015-08-29 15:06:31.893 [INFO] [actors.PlatService] in application-akka.actor.default-dispatcher-17 
body is AnyContentAsText({})

2015-08-29 15:08:23.935 [INFO] [actors.PlatService] in application-akka.actor.default-dispatcher-18 
body is AnyContentAsJson({})

AnyContentAsMultipartFormData just cannot be received.

I'm wondering if there is a way to solve this problem?

After a little more test, I encountered this exception:

2015-08-30 16:02:01.787 [ERROR] [akka.remote.EndpointWriter] in application-akka.actor.default-dispatcher-5 
Transient association error (association remains live)
java.io.NotSerializableException: scala.collection.immutable.MapLike$$anon$2
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) ~[na:1.8.0_45]
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) ~[na:1.8.0_45]
    at akka.serialization.JavaSerializer$$anonfun$toBinary$1.apply$mcV$sp(Serializer.scala:234) ~[com.typesafe.akka.akka-actor_2.11-2.4.0-RC1.jar:na]
    at akka.serialization.JavaSerializer$$anonfun$toBinary$1.apply(Serializer.scala:234) ~[com.typesafe.akka.akka-actor_2.11-2.4.0-RC1.jar:na]
    at akka.serialization.JavaSerializer$$anonfun$toBinary$1.apply(Serializer.scala:234) ~[com.typesafe.akka.akka-actor_2.11-2.4.0-RC1.jar:na]
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58) ~[org.scala-lang.scala-library-2.11.6.jar:na]
    at akka.serialization.JavaSerializer.toBinary(Serializer.scala:234) ~[com.typesafe.akka.akka-actor_2.11-2.4.0-RC1.jar:na]
    at akka.remote.serialization.MessageContainerSerializer.serializeSelection(MessageContainerSerializer.scala:45) ~[com.typesafe.akka.akka-remote_2.11-2.4.0-RC1.jar:na]
    at akka.remote.serialization.MessageContainerSerializer.toBinary(MessageContainerSerializer.scala:34) ~[com.typesafe.akka.akka-remote_2.11-2.4.0-RC1.jar:na]
    at akka.remote.MessageSerializer$.serialize(MessageSerializer.scala:37) ~[com.typesafe.akka.akka-remote_2.11-2.4.0-RC1.jar:na]
    at akka.remote.EndpointWriter$$anonfun$serializeMessage$1.apply(Endpoint.scala:837) ~[com.typesafe.akka.akka-remote_2.11-2.4.0-RC1.jar:na]
    at akka.remote.EndpointWriter$$anonfun$serializeMessage$1.apply(Endpoint.scala:837) ~[com.typesafe.akka.akka-remote_2.11-2.4.0-RC1.jar:na]
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58) ~[org.scala-lang.scala-library-2.11.6.jar:na]
    at akka.remote.EndpointWriter.serializeMessage(Endpoint.scala:836) ~[com.typesafe.akka.akka-remote_2.11-2.4.0-RC1.jar:na]
    at akka.remote.EndpointWriter.writeSend(Endpoint.scala:737) ~[com.typesafe.akka.akka-remote_2.11-2.4.0-RC1.jar:na]
    at akka.remote.EndpointWriter$$anonfun$4.applyOrElse(Endpoint.scala:712) ~[com.typesafe.akka.akka-remote_2.11-2.4.0-RC1.jar:na]
    at akka.actor.Actor$class.aroundReceive(Actor.scala:480) ~[com.typesafe.akka.akka-actor_2.11-2.4.0-RC1.jar:na]
    at akka.remote.EndpointActor.aroundReceive(Endpoint.scala:405) ~[com.typesafe.akka.akka-remote_2.11-2.4.0-RC1.jar:na]
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:525) [com.typesafe.akka.akka-actor_2.11-2.4.0-RC1.jar:na]
    at akka.actor.ActorCell.invoke(ActorCell.scala:494) [com.typesafe.akka.akka-actor_2.11-2.4.0-RC1.jar:na]
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257) [com.typesafe.akka.akka-actor_2.11-2.4.0-RC1.jar:na]
    at akka.dispatch.Mailbox.run(Mailbox.scala:224) [com.typesafe.akka.akka-actor_2.11-2.4.0-RC1.jar:na]
    at akka.dispatch.Mailbox.exec(Mailbox.scala:234) [com.typesafe.akka.akka-actor_2.11-2.4.0-RC1.jar:na]
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) [org.scala-lang.scala-library-2.11.6.jar:na]
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) [org.scala-lang.scala-library-2.11.6.jar:na]
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) [org.scala-lang.scala-library-2.11.6.jar:na]
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) [org.scala-lang.scala-library-2.11.6.jar:na]

It seems that this might be the problem. But I don't know how to solve it.

Any message or instruction is really appreciated. Thanks in advance.

1
So, you get no error message? - Kris
I take a guess: It has something to do with lazy loading of MultipartFormData and Akka doesn't like mutable state of it's Actors. Try getting all data out of the MultipartFormData before you hand it to your Actor. - Kris
Thanks for your kind answer. But the problem just occurs between nodes. If the message were sent inside one node, then there was no any missing. However, if the message is between nodes, then MultipartFormData won't be seen in the remote node. - Wayne Wang

1 Answers

1
votes

When you send messages inbetween nodes it needs to be serialized, since they do not share memory like the actor system inside of the play app does. What the error message says is that it came upon an object it cannot serialize, it even is friendly enough to tell you exactly what object it could not serialize, in this case scala.collection.immutable.MapLike$$anon$2 the word "anon" hints that it is something that is anonymous, like an anonymous inner class or an anonymous function. So, the play MultipartFormData accepts a Map which in this case probably is something play internal wrapped in Maps clothes so to speak.

I would avoid sending instances of play specific classes at all in between nodes and instead have a clear protocol of your own message classes containing your own model classes and immutable collection objects. This will have the additional benefit of being much easier to test and entirely removing the need to load play classes in the akka nodes.