【问题标题】:How to connect to Mongo DB in Docker from Scala Play Framework?如何从 Scala Play 框架连接到 Docker 中的 Mongo DB?
【发布时间】:2021-12-30 22:54:21
【问题描述】:

我有一个在 192.168.0.229 上运行的 Mongo DB Docker 容器。在另一台计算机上,我可以通过以下方式访问它:

> mongo "mongodb://192.168.0.229:27017/test"

但是当我将该配置字符串 (host="192.168.0.229") 添加到我的 Play Framework 应用程序时,我收到超时错误:

[debug] application - Login Form Success: UserData(larry@gmail.com,testPW)
[error] p.a.h.DefaultHttpErrorHandler - 

! @7m7kggikl - Internal server error, for (POST) [/] ->
 
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[TimeoutException: Future timed out after [30 seconds]]]

过去,使用host="localhost" 连接成功,甚至使用Atlas 集群(host="mycluster.gepld.mongodb.net") 作为主机名,因此之前使用相同代码连接没有问题。出于某种原因,Play Framework 不想连接到此端点!

可能是因为主机名是 IP 地址吗?或者,也许 Play/Akka 在幕后做了一些事情来停止连接(或者让 Mongo/Docker 拒绝接受它?)?

我正在使用这个驱动程序:

"org.mongodb.scala" %% "mongo-scala-driver" % "4.4.0"

也许我应该切换到反应式 Scala 驱动程序?任何帮助将不胜感激。


说明: Mongo DB Docker 容器在我的本地网络上的一台 linux 机器上运行。可以从我的本地网络192.168.0.229 访问此容器。目标是将我的 Play Framework 应用程序配置设置为指向该地址的数据库,这样只要 Docker 容器正在运行,我就可以在本地网络上的任何计算机上进行开发。目前,我可以在任何计算机上通过 mongo shell 访问容器:

> mongo "mongodb://192.168.0.229:27017/test"

我有一个 Play Framework 应用,在 Application.conf 中包含以下内容:

datastore {
     # Dev
      host: "192.168.0.229"
      port: 27017
      dbname: "test"
      user: ""
      password: ""
}

此数据用于名为DataStore.scala 的连接帮助文件:

package model.db.mongo

import org.mongodb.scala._
import utils.config.AppConfiguration

trait DataStore extends AppConfiguration {

  lazy val dbHost = config.getString("datastore.host")
  lazy val dbPort = config.getInt("datastore.port")
  lazy val dbUser = getConfigString("datastore.user", "")
  lazy val dbName =  getConfigString("datastore.dbname", "")
  lazy val dbPasswd = getConfigString("datastore.password", "")

  //MongoDB Atlas Method (Localhost if DB User is empty)
  val uri: String = s"mongodb+srv://$dbUser:$dbPasswd@$dbHost/$dbName?retryWrites=true&w=majority"
  //val uri: String = "mongodb+svr://192.168.0.229:27017/?compressors=disabled&gssapiServiceName=mongodb"
  System.setProperty("org.mongodb.async.type", "netty")
  val mongoClient: MongoClient = if (getConfigString("datastore.user", "").isEmpty()) MongoClient() else MongoClient(uri)
  print(mongoClient.toString)
  print(mongoClient.listDatabaseNames())
  val database: MongoDatabase = mongoClient.getDatabase(dbName)
  def close = mongoClient.close() //Do this when logging out
}

当您启动应用程序时,您会打开localhost:9000,这只是一个登录表单。当您填写与users集合中的数据对应的数据时,Play应用程序超时:

[error] p.a.h.DefaultHttpErrorHandler - 

! @7m884abc4 - Internal server error, for (POST) [/] ->
 
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[TimeoutException: Future timed out after [30 seconds]]]
    at play.api.http.HttpErrorHandlerExceptions$.$anonfun$convertToPlayException$2(HttpErrorHandler.scala:381)
    at scala.Option.map(Option.scala:242)
    at play.api.http.HttpErrorHandlerExceptions$.convertToPlayException(HttpErrorHandler.scala:380)
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:373)
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:264)
    at play.core.server.AkkaHttpServer$$anonfun$2.applyOrElse(AkkaHttpServer.scala:430)
    at play.core.server.AkkaHttpServer$$anonfun$2.applyOrElse(AkkaHttpServer.scala:422)
    at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:454)
    at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:63)
    at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:100)
Caused by: java.util.concurrent.TimeoutException: Future timed out after [30 seconds]
    at scala.concurrent.impl.Promise$DefaultPromise.tryAwait0(Promise.scala:212)
    at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:225)
    at scala.concurrent.Await$.$anonfun$result$1(package.scala:201)
    at akka.dispatch.MonitorableThreadFactory$AkkaForkJoinWorkerThread$$anon$3.block(ThreadPoolBuilder.scala:174)
    at java.base/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3118)
    at akka.dispatch.MonitorableThreadFactory$AkkaForkJoinWorkerThread.blockOn(ThreadPoolBuilder.scala:172)
    at akka.dispatch.BatchingExecutor$BlockableBatch.blockOn(BatchingExecutor.scala:116)
    at scala.concurrent.Await$.result(package.scala:124)
    at model.db.mongo.DataHelpers$ImplicitObservable.headResult(DataHelpers.scala:27)
    at model.db.mongo.DataHelpers$ImplicitObservable.headResult$(DataHelpers.scala:27)

对用户集合的调用在UserAccounts.scala中定义:

case class UserAccount(_id: String, fullname: String, username: String, password: String)

object UserAccount extends DataStore {

  val logger: Logger = Logger("database")

  //Required for using Case Classes
  val codecRegistry = fromRegistries(fromProviders(classOf[UserAccount]), DEFAULT_CODEC_REGISTRY)

  //Using Case Class to get a collection
  val coll: MongoCollection[UserAccount] = database.withCodecRegistry(codecRegistry).getCollection("users")

  //Using Document to get a collection
  val listings: MongoCollection[Document] = database.getCollection("users")

  def isValidLogin(username: String, password: String): Boolean = {
    findUser(username) match {
      case Some(u: UserAccount)  => if(password.equals(u.password)) { true } else {false }
      case None  => false
    }
  }

【问题讨论】:

  • 你能发布你用于数据库连接的整个配置 + 整个堆栈跟踪 + 调用 Mongo 的相关代码吗?
  • 澄清一下:Play 应用是在容器中运行还是直接在您的机器上运行?
  • 感谢您对@GaëlJ 发表评论。我已经用更多细节更新了这个问题。对于 Play 应用的所有相关部分,如果我没有提供您要求的所有信息,请告诉我。
  • 您是否调试了连接字符串。在我看来,您使用的是空用户和密码,但仍在它们之间输出:
  • 是的,我使用了它下面的注释行。

标签: mongodb docker scala playframework


【解决方案1】:

如果有人遇到此问题,仅供参考。我的DataStore.scala 文件中有一行错误:

val mongoClient: MongoClient = if (getConfigString("datastore.user", "").isEmpty()) MongoClient() else MongoClient(uri)

因为我试图在没有用户名的情况下进行连接(我的测试数据库上没有身份验证),所以上面的行说:“如果没有用户名,您必须尝试连接到默认的 MongoClient() 位置,即本地主机”。我的错。

我只是将上面的行改为:

val mongoClient: MongoClient = MongoClient(uri)

【讨论】:

    猜你喜欢
    • 2016-06-17
    • 1970-01-01
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多