No primary node available

58 views
Skip to first unread message

Kilic Ali-Firat

unread,
Dec 3, 2016, 5:05:05 AM12/3/16
to ReactiveMongo - http://reactivemongo.org
Hi,

In one akka project, I use reactivemongo to save metadata, I get sometimes the following error :

reactivemongo mongoerror 'no primary node is available



First, I'm using the last version of reactivemongo.

"org.reactivemongo" % "play2-reactivemongo_2.11" % "0.12.0-play24"



 I read some topics about this error and I know there are so deprecated functions to not use (like db.collection) so below the code used to communicate with mongodb :

// Scala
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{ Await, Future }
import scala.util.{ Try, Failure, Success }
import scala.concurrent.duration._


// ReactiveMongo
import reactivemongo.api.{ DefaultDB, MongoConnection, MongoDriver }
import reactivemongo.play.json.collection.JSONCollection


// TypeSafe
import com.typesafe.scalalogging._
import com.typesafe.config.ConfigFactory




/**
  * Database basic operations.
  */

object Database extends LazyLogging {


 
/**
    * Because we are in a singleton, the drive will be create juste
    * once.
    */

 
private val driver = new MongoDriver


 
/**
    * Create a connection to an existing mongo database name
    * @param mongoURI the URI of mongo server
    * @param mongoDatabase the mongo database name
    * @return a Future with an Option indicating if the connection is
    * successful or not.
    */

 
def createConnection
   
(
      mongoURI
: String
   
) : Try[MongoConnection] =
   
MongoConnection
     
.parseURI(mongoURI)
     
.map(parsedUri => driver.connection(parsedUri))


 
/**
    * Get a collection from reactivemongo
    * @param mongoURI the URI of mongo server
    * @param mongoDatabase the mongo database name
    * @param mongoCollectionName the mongo collection name
    */

 
def getFutureDatabase
   
(
      mongoConnectionOpt
: Try[MongoConnection],
      mongoDatabase
: String
   
): Future[DefaultDB] = {
    mongoConnectionOpt match
{
     
case Success(connection) =>
        connection
.database(mongoDatabase)
     
case Failure(e) =>
        logger
.info("Error when connectiong to the mongo server -> " + e)
       
Future { null }
   
}
 
}


 
def getFutureCollection
   
(
      mongoDatabase
: Future[DefaultDB],
      mongoCollectionName
: String
   
) : Future[JSONCollection] = {
    mongoDatabase map
(_.collection(mongoCollectionName))
 
}


The error comes when I try to create a new JSON document like this : 

case class BFF_MongoIO(futureCollection: Future[JSONCollection]) extends LazyLogging {


 
def createRecord(record: CCWBiosRecord): Future[WriteResult] = {
    futureCollection flatMap
(_.insert(record))
 
}

I'm using this code in an Akka actors application. I wrote a Main in which I created all the actors of my actor system but also all the mongo requirements to communicate with it my collections :


 
     
 
  val mongoURI = config.getString("mongo.uri")


    val connectionOpt
: Try[MongoConnection] =
     
Database.createConnection(mongoURI)


   
/**
      * Mongo DB Name
      */

    val mongoDBName
= config.getString("mongo.database")




   
def futureDB : Future[DefaultDB] =
     
Database.getFutureDatabase(connectionOpt,mongoDBName)


   
/**
      * Reactivemongo collection name with records metadata
      */

   
def bffCollectionName = config.getString("mongo.collection_bff")


    logger
.info("bff collection name = " + bffCollectionName)


   
def eventCollectionName = config.getString("mongo.collection_bff_events")


    logger
.info("bff events collection name = " + eventCollectionName)


   
def futureBFFCollection : Future[JSONCollection] =
     
Database.getFutureCollection(futureDB, bffCollectionName)


   
def futureEventsCollection : Future[JSONCollection] =
     
Database.getFutureCollection(futureDB, eventCollectionName)


val listener
=
      system
       
.actorOf(KafkaStartStreamListener.props(kafkaProps, kafkaPollTimeout, streamingListener, kafkaEventsListener, futureBFFCollection, None), name = "UP_DOWN_Listener_Actor")


In the above actor, I'm calling the function createRecord like this :

val futureCreate = bff_MongoIO.createRecord(record)
            futureCreate onComplete
{
             
case Success(s) => ()                
             
case Failure(e) =>
                log
.error("Error when create record {} ", e)
           
}



In a previous version of my code, I was using an old version of play2-reactivemongo_2.11 (0.11.4) and when I updated this lib version, the error came less often. 

But what I want to know is that if I'm doing a wrong thing about the way to create the mongodb collections or their uses. From the last mongodb documentation, I read that dababase and collections should be assisgned to def and not val. In my case, I'm doing this but I wrapped them in a Future, is it change something in the reactivemongo side  ?

Many thanks !




Cédric Chantepie

unread,
Dec 4, 2016, 7:54:51 AM12/4/16
to ReactiveMongo - http://reactivemongo.org
Hi,

The following futureCollection is a val, which is discouraged.

case class BFF_MongoIO(futureCollection: Future[JSONCollection
])

Then, it's recommanded you check the latency between your app the the node set. There are some options you can adjust : http://reactivemongo.org/releases/0.12/documentation/tutorial/connect-database.html
  • Something like Future { null } is not recommanded.

Kilic Ali-Firat

unread,
Dec 8, 2016, 3:19:03 AM12/8/16
to ReactiveMongo - http://reactivemongo.org
Hello, 

I changed my API and assign the futureCollection to a def works without getting the exception. 
Reply all
Reply to author
Forward
0 new messages