Skip to content
This repository has been archived by the owner on Nov 18, 2024. It is now read-only.

Commit

Permalink
Merge pull request #73 from hmrc/BDOG-538
Browse files Browse the repository at this point in the history
BDOG-538 adds optional network diagnostics, updates .count
  • Loading branch information
christopherjturner authored Dec 31, 2019
2 parents 2a93e70 + 7b34e50 commit 8cc1694
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/main/scala/play/modules/reactivemongo/MongoConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class MongoConfig(
.orElse(configuration.getOptional[Configuration](s"${environment.mode}.mongodb"))
.orElse(configuration.getOptional[Configuration](s"${Mode.Dev}.mongodb"))
.getOrElse(throw new Exception("The application does not contain required mongodb configuration"))

lazy val diagnostics: Boolean = mongoConfig.getBoolean("diagnostics").getOrElse(false)
}

private object DelayFactor extends (Option[Configuration] => Int => Double) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@

package play.modules.reactivemongo

import java.net.{InetAddress, Socket}

import com.google.inject.{ImplementedBy, Inject, Singleton}
import play.api._
import play.api.inject.{ApplicationLifecycle, Binding, Module}
import reactivemongo.api.MongoConnection
import uk.gov.hmrc.mongo.MongoConnector

import scala.concurrent.Future
import scala.util.{Failure, Try}

class ReactiveMongoHmrcModule extends Module {
def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] =
Expand Down Expand Up @@ -50,12 +54,17 @@ class ReactiveMongoComponentImpl @Inject()(

private lazy val mongoConfig = new MongoConfig(environment, configuration)

lazy val mongoConnector: MongoConnector = MongoConnector(
mongoConfig.uri,
mongoConfig.maybeFailoverStrategy,
mongoConfig.dbTimeout
)
val mongoConnector: MongoConnector = {

if(mongoConfig.diagnostics) MongoDiagnostics.runAll(mongoConfig)

MongoConnector(
mongoConfig.uri,
mongoConfig.maybeFailoverStrategy,
mongoConfig.dbTimeout
)

}
Logger.debug(s"ReactiveMongoPlugin: MongoConnector configuration being used: $mongoConnector")

lifecycle.addStopHook { () =>
Expand All @@ -65,3 +74,50 @@ class ReactiveMongoComponentImpl @Inject()(
}
}
}

object MongoDiagnostics {

def runAll(config: MongoConfig):Unit = Try {
Logger.info("Running mongo diagnostics")
logConfig(config)
validateDNS(config)
validateNetworkConnectivity(config)
Logger.info("Mongo diagnostics complete")
}

private def logConfig(config: MongoConfig): Unit = {
MongoConnection.parseURI(config.uri)
.foreach(puri => {
Logger.info(s"Mongo auth set: ${puri.authenticate.isDefined}")
Logger.info(s"Mongo database: ${puri.db.getOrElse("Not Set")}")
Logger.info(s"Mongo nodelist: ${puri.hosts.mkString(",")}")
})
}

private def validateDNS(config: MongoConfig):Unit = {
MongoConnection.parseURI(config.uri).foreach { parsedUri =>
parsedUri.hosts.map(_._1).foreach { host =>
InetAddress.getAllByName(host).map(_.getAddress.map(_.toInt).mkString(".")).foreach(ip => Logger.info(s"Mongo node [$host] resolves to $ip"))
}
}
}

private def validateNetworkConnectivity(mongoConfig: MongoConfig) : Unit = Try {
Logger.info("Testing mongo network connectivity...")
MongoConnection.parseURI(mongoConfig.uri).foreach { parsedUri =>
parsedUri.hosts.foreach( hp => validateConnection(hp._1, hp._2))
}
}

private def validateConnection(host:String, port:Int): Unit = Try {
val s = new Socket(host, port)
Logger.info(s"[$host:$port](${s.getInetAddress.toString}) connected: ${s.isConnected}, is network reachable: ${Try(s.getInetAddress.isReachable(20)).getOrElse(false)}")
s.close()
}.recoverWith {
case ex: Throwable => {
Logger.info(s"[$host:$port] Mongo network connectivity failed")
Failure(ex)
}
}

}
15 changes: 11 additions & 4 deletions src/main/scala/uk/gov/hmrc/mongo/ReactiveRepository.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import play.api.libs.json.{Format, JsObject, Json}
import reactivemongo.api.Cursor.FailOnError
import reactivemongo.api.commands._
import reactivemongo.api.indexes.Index
import reactivemongo.api.{DB, ReadPreference}
import reactivemongo.api.{DB, ReadConcern, ReadPreference}
import reactivemongo.core.errors.GenericDatabaseException
import reactivemongo.play.json.ImplicitBSONHandlers
import reactivemongo.play.json.collection.JSONCollection
Expand Down Expand Up @@ -99,11 +99,18 @@ abstract class ReactiveRepository[A, ID](
arrayFilters = arrayFilters
)

def count(implicit ec: ExecutionContext): Future[Int] = count(Json.obj())
def count(implicit ec: ExecutionContext): Future[Int] = count(None, ReadPreference.primary)

def count(query: JsObject, readPreference: ReadPreference = ReadPreference.primary)(
implicit ec: ExecutionContext): Future[Int] = count(Some(query), readPreference)

private def count(query: Option[JsObject], readPreference: ReadPreference)(
implicit ec: ExecutionContext): Future[Int] =
collection.withReadPreference(readPreference).count(Some(query))
collection.withReadPreference(readPreference).count(selector = query,
limit = None,
skip = 0,
hint = None,
readConcern = ReadConcern.Available).map(_.toInt)

def removeAll(writeConcern: WriteConcern = WriteConcern.Default)(implicit ec: ExecutionContext): Future[WriteResult] =
collection.delete(ordered = true, writeConcern).one(Json.obj(), None)
Expand All @@ -128,7 +135,7 @@ abstract class ReactiveRepository[A, ID](

def insert(entity: A)(implicit ec: ExecutionContext): Future[WriteResult] =
domainFormat.writes(entity) match {
case d @ JsObject(_) => collection.insert(d)
case d @ JsObject(_) => collection.insert(false).one(d)
case _ =>
Future.failed[WriteResult](new Exception("cannot write object") with NoStackTrace)
}
Expand Down

0 comments on commit 8cc1694

Please sign in to comment.