Я использую Play 2.3 и Akka, чтобы настроить простой протокол подписки на публикацию через веб-сокет. В рамках этого протокола после подписки клиента сервер отправляет исходное состояние из базы данных.
Мой текущий код работает изначально, но во время разработки запрос Morphia внутри сокета Iteratee перестает работать после перезагрузки разработки. Регулярные запросы, даже запросы, которые делают один и тот же запрос, продолжают работать нормально.
Я использую подключаемый модуль распределенного суб-посредника паба Akka. Вот соответствующий код для актера, представляющего слушателя веб-сокета:
object Subscriber {
def props(channel: Concurrent.Channel[JsValue]): Props = Props(new Subscriber(channel))
}
class Subscriber(channel: Concurrent.Channel[JsValue]) extends Actor {
def receive = {
case StatusUpdate(...) =>
channel.push(...)
}
}
И для контроллера главного представления:
object SocketController extends Controller {
val mediator = DistributedPubSubExtension.get(Akka.system).mediator
def index = WebSocket.using[JsValue] { implicit request =>
val (out, channel) = Concurrent.broadcast[JsValue]
val ws = Akka.system.actorOf(Subscriber.props(channel))
val in = Iteratee.foreach[JsValue] { msg =>
(msg \ "type").as[String] match {
case "Subscribe" =>
val target = (msg \ "value").as[String]
// Query database with Morphia
val current = MyObj.findByName(target)
// Notify of current state
ws ! StatusUpdate(target, current)
// Subscribe for further updates
mediator ! DistributedPubSubMediator.Subscribe(target, ws)
}
}
(in, out)
}
}
Проблема возникает в операторе запроса в итерации. После перезарядки Морфия бросает org.mongodb.morphia.mapping.MappingException: Could not map models.MyObj with ID: 5507a3653004b8a9e8f3d3b2
. Вот полный след:
org.mongodb.morphia.mapping.MappingException: Could not map models.MyObj with ID: 5507a3653004b8a9e8f3d3b2
at org.mongodb.morphia.mapping.Mapper.fromDb(Mapper.java:594)
at org.mongodb.morphia.mapping.Mapper.fromDBObject(Mapper.java:299)
at org.mongodb.morphia.query.MorphiaIterator.convertItem(MorphiaIterator.java:79)
at org.mongodb.morphia.query.MorphiaIterator.processItem(MorphiaIterator.java:65)
at org.mongodb.morphia.query.MorphiaIterator.next(MorphiaIterator.java:60)
at org.mongodb.morphia.query.QueryImpl.get(QueryImpl.java:402)
at models.MyObj$.findByName(MyObj.scala:99)
at controllers.MyObj$$anonfun$MyObj$1$$anonfun$4.apply(MyObj.scala:99)
at controllers.MyObj$$anonfun$MyObj$1$$anonfun$4.apply(MyObj.scala:93)
at play.api.libs.iteratee.Iteratee$$anonfun$foreach$1.apply(Iteratee.scala:201)
at play.api.libs.iteratee.Iteratee$$anonfun$foreach$1.apply(Iteratee.scala:201)
at play.api.libs.iteratee.Iteratee$$anonfun$fold$1$$anonfun$apply$1.apply(Iteratee.scala:41)
at play.api.libs.iteratee.internal$.eagerFuture(package.scala:30)
at play.api.libs.iteratee.Iteratee$$anonfun$fold$1.apply(Iteratee.scala:41)
at play.api.libs.iteratee.Iteratee$$anonfun$fold$1.apply(Iteratee.scala:41)
at play.api.libs.iteratee.Iteratee$$anonfun$1.apply(Iteratee.scala:60)
at play.api.libs.iteratee.Iteratee$$anonfun$1.apply(Iteratee.scala:60)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:41)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: org.mongodb.morphia.mapping.MappingException: Error setting value from converter (ObjectIdConverter) for models.MyObj.id to 5507a3653004b8a9e8f3d3b2
at org.mongodb.morphia.converters.DefaultConverters.fromDBObject(DefaultConverters.java:137)
at org.mongodb.morphia.mapping.ValueMapper.fromDBObject(ValueMapper.java:27)
at org.mongodb.morphia.mapping.Mapper.readMappedField(Mapper.java:608)
at org.mongodb.morphia.mapping.Mapper.fromDb(Mapper.java:589)
... 24 more
Caused by: java.lang.IllegalArgumentException: Can not set org.bson.types.ObjectId field models.MyObj.id to models.MyObj
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
at java.lang.reflect.Field.set(Field.java:758)
at org.mongodb.morphia.mapping.MappedField.setFieldValue(MappedField.java:508)
at org.mongodb.morphia.converters.DefaultConverters.fromDBObject(DefaultConverters.java:135)
... 27 more
Это исключение происходит только в обработчике веб-сокетов, обычный запрос может выполнить запрос. Полный перезапуск сервера разработки устраняет проблему до следующей перезагрузки.
Вот журналы консоли после запуска и одного перезапуска: http://pastebin.com/xsstw4ki
Есть мысли о том, что здесь может происходить? Другие ссылки, которые я нашел для этой ошибки, кажутся несвязанными или старый.
Обновление - 4 июля 2015 г.
Также бывает в Play 2.4.2.