【发布时间】: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