简体   繁体   中英

How to insert into MongoDB from actor using Casbah?

Assumptions:

  • MongoDB is running at localhost:27017

  • This project is modeled after https://github.com/sap1ens/akka-microservice . Please refer to it if there is not enough information below to help. If it gets too confusing, I can add code from other files if necessary.

Questions based on RegistrationsService.scala

  • Why is it trying to connect to MongoDB and insert the document on startup before any PostRegistrationMessage is sent to RegistrationsService actor?

  • Why is it failing?

  • How can I convert registrationJsValue into MongoDBObject and insert it into collection?

Relevant info in build.sbt

scalaVersion := "2.10.4"

val akkaVersion = "2.3.8"

val sprayVersion = "1.3.1"

// Main dependencies
libraryDependencies ++= Seq(
    "com.typesafe.akka" %% "akka-actor" % akkaVersion,
    "com.typesafe.akka" %% "akka-slf4j" % akkaVersion,
    "io.spray" % "spray-can" % sprayVersion,
    "io.spray" % "spray-routing" % sprayVersion,
    "io.spray" % "spray-client" % sprayVersion,
    "io.spray" %% "spray-json" % sprayVersion,
    "com.typesafe" % "config" % "1.2.1",
    "ch.qos.logback" % "logback-classic" % "1.1.2",
    "org.mongodb" %% "casbah" % "2.7.4"
)

RegistrationService.scala (like ExampleService.scala in git repo)

package service

import akka.actor.{Props, ActorLogging, Actor}
import spray.json._
import com.mongodb.util.JSON
import com.mongodb.casbah.Imports._
import model.Registration
import model.RegistrationProtocol._

object RegistrationsService {
  case class PostRegistrationMessage(registration: Registration)

  def props(property: String) = Props(classOf[RegistrationsService], property)
}

class RegistrationsService(property: String) extends Actor with ActorLogging {
  import RegistrationsService._

  def receive = {
    case PostRegistrationMessage(registration) => {

      val registrationJsValue = registration.toJson
      val dbObject = JSON.parse(registrationJsValue.toString()).asInstanceOf[DBObject]

      val mongoClientURI = MongoClientURI("mongodb://localhost:27017/")
      val mongoClient = MongoClient(mongoClientURI)
      val someDB = mongoClient("somedb")
      val registrationsColl = someDB("registratoins")
      log.info(s"Got access to registratoins collection")

      registrationsColl.insert(MongoDBObject("hello" -> "world"))
      log.info(s"Inserted a doc to registratoins collection")

      mongoClient.close()
      log.info(s"Closed client connection to mongo")

      sender() ! registrationJsValue
    }
  }
}

sbt run

14:01:10.655 [microservice-system-akka.actor.default-dispatcher-3] INFO  c.e.a.s.RegistrationsService - Got access to registratoins collection
14:01:11.383 [microservice-system-akka.actor.default-dispatcher-3] DEBUG spray.can.server.HttpListener - Binding to localhost/127.0.0.1:8878
14:01:11.475 [microservice-system-akka.actor.default-dispatcher-3] DEBUG akka.io.TcpListener - Successfully bound to /127.0.0.1:8878
14:01:11.480 [microservice-system-akka.actor.default-dispatcher-6] INFO  spray.can.server.HttpListener - Bound to localhost/127.0.0.1:8878
14:01:20.704 [microservice-system-akka.actor.default-dispatcher-5] ERROR akka.actor.OneForOneStrategy - Timed out after 10000 ms while waiting for a server that matches AnyServerSelector{}. Client view of cluster state is {type=Unknown, servers=[{address=localhost:27017, type=Unknown, state=Connecting, exception={java.lang.NullPointerException}}]
com.mongodb.MongoTimeoutException: Timed out after 10000 ms while waiting for a server that matches AnyServerSelector{}. Client view of cluster state is {type=Unknown, servers=[{address=localhost:27017, type=Unknown, state=Connecting, exception={java.lang.NullPointerException}}]
    at com.mongodb.BaseCluster.getServer(BaseCluster.java:82) ~[mongo-java-driver-2.12.4.jar:na]
    at com.mongodb.DBTCPConnector.getServer(DBTCPConnector.java:654) ~[mongo-java-driver-2.12.4.jar:na]
    at com.mongodb.DBTCPConnector.access$300(DBTCPConnector.java:39) ~[mongo-java-driver-2.12.4.jar:na]
    at com.mongodb.DBTCPConnector$MyPort.getConnection(DBTCPConnector.java:503) ~[mongo-java-driver-2.12.4.jar:na]
    at com.mongodb.DBTCPConnector$MyPort.get(DBTCPConnector.java:451) ~[mongo-java-driver-2.12.4.jar:na]
    at com.mongodb.DBTCPConnector.getPrimaryPort(DBTCPConnector.java:409) ~[mongo-java-driver-2.12.4.jar:na]
    at com.mongodb.DBCollectionImpl.insert(DBCollectionImpl.java:182) ~[mongo-java-driver-2.12.4.jar:na]
    at com.mongodb.DBCollectionImpl.insert(DBCollectionImpl.java:165) ~[mongo-java-driver-2.12.4.jar:na]
    at com.mongodb.DBCollection.insert(DBCollection.java:93) ~[mongo-java-driver-2.12.4.jar:na]
    at com.mongodb.casbah.MongoCollectionBase$class.insert(MongoCollection.scala:621) ~[casbah-core_2.10-2.7.4.jar:2.7.4]
    at com.mongodb.casbah.MongoCollection.insert(MongoCollection.scala:1109) ~[casbah-core_2.10-2.7.4.jar:2.7.4]
    at service.RegistrationsService$$anonfun$receive$1.applyOrElse(RegistrationsService.scala:47) ~[classes/:na]
    at akka.actor.Actor$class.aroundReceive(Actor.scala:465) ~[akka-actor_2.10-2.3.8.jar:na]
    at service.RegistrationsService.aroundReceive(RegistrationsService.scala:20) ~[classes/:na]
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:516) [akka-actor_2.10-2.3.8.jar:na]
    at akka.actor.ActorCell.invoke(ActorCell.scala:487) [akka-actor_2.10-2.3.8.jar:na]
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:254) [akka-actor_2.10-2.3.8.jar:na]
    at akka.dispatch.Mailbox.run(Mailbox.scala:221) [akka-actor_2.10-2.3.8.jar:na]
    at akka.dispatch.Mailbox.exec(Mailbox.scala:231) [akka-actor_2.10-2.3.8.jar:na]
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) [scala-library.jar:na]
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) [scala-library.jar:na]
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) [scala-library.jar:na]
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) [scala-library.jar:na]
^C14:01:42.231 [microservice-system-akka.actor.default-dispatcher-11] INFO  akka.actor.LocalActorRef - Message [akka.actor.Terminated] from Actor[akka://microservice-system/user/$a#1754981697] to Actor[akka://microservice-system/user/IO-HTTP/listener-0#-602059531] was not delivered. [1] 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'.
14:01:42.236 [microservice-system-akka.actor.default-dispatcher-11] DEBUG akka.event.EventStream - shutting down: StandardOutLogger started

Not sure what you mean by the following.

Why is it trying to connect to MongoDB and insert the document on startup before any PostRegistrationMessage is sent to RegistrationsService actor?

In the example code (for RegistrationsService ) you have shown the only connection that is made is inside the Actor's receive method. Unless you (or some other piece of code is sending this message, the actor will not try to connect to Mongo.

On a side note, what are you creating a Mongo connection inside the Actor's receive method ? You should avoid any heavy weight operation inside the receive method. You can create a Mongo connection outside the Actor and then inject it in the Actor's constructor to be used in the Receive method.

Have you written a standalone program/test that connects to your MongoDB using the casbah driver? It should work independently of your actor code and will help your isolate any issues (if there is one) with the driver and connection code.

PS: This may not the be the answer to your question but I didn't want to write it in the comments part because of space and formatting limitations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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