MongoDB的 - 不能调用ClusterDescription.getConnectionMode,因为clusterDescription为空

问题描述

我想实现与Ktor和KMongo一个RESTful API。我连接的MongoDB阿特拉斯数据库和它工作得很好。

然后我准备部署在Heroku API的第一个版本,现在当我本地运行的每个查询数据库抛出此异常:

2021-01-07 15:10:30.211 [eventLoopGroupProxy-4-2] INFO  org.mongodb.driver.cluster - Cluster created with settings {hosts=[127.0.0.1:27017],srvHost=cluster0.euib1.mongodb.net,mode=MULTIPLE,requiredClusterType=REPLICA_SET,serverSelectionTimeout='30000 ms',maxWaitQueueSize=500,requiredreplicasetName='atlas-hl2rus-shard-0'}
15:10:30 web.1   |  2021-01-07 15:10:30.258 [cluster-ClusterId{value='5ff7165648f4085f7af773f9',description='null'}-srv-cluster0.euib1.mongodb.net] INFO  org.mongodb.driver.cluster - Adding discovered server cluster0-shard-00-00.euib1.mongodb.net:27017 to client view of cluster
15:10:30 web.1   |  2021-01-07 15:10:30.268 [eventLoopGroupProxy-4-2] ERROR Application - Unhandled: GET - /books
15:10:30 web.1   |  java.lang.NullPointerException: Cannot invoke "com.mongodb.connection.ClusterDescription.getConnectionMode()" because "clusterDescription" is null
15:10:30 web.1   |      at com.mongodb.async.client.ClientSessionHelper.getServerDescriptionListToConsiderForSessionSupport(ClientSessionHelper.java:107)
15:10:30 web.1   |      at com.mongodb.async.client.ClientSessionHelper.createClientSession(ClientSessionHelper.java:63)
15:10:30 web.1   |      at com.mongodb.async.client.ClientSessionHelper.withClientSession(ClientSessionHelper.java:51)
15:10:30 web.1   |      at com.mongodb.async.client.OperationExecutorImpl.execute(OperationExecutorImpl.java:66)
15:10:30 web.1   |      at com.mongodb.async.client.MongoIterableImpl.batchCursor(MongoIterableImpl.java:161)
15:10:30 web.1   |      at com.mongodb.async.client.MongoIterableSubscription.requestinitialData(MongoIterableSubscription.java:46)
15:10:30 web.1   |      at com.mongodb.async.client.AbstractSubscription.tryRequestinitialData(AbstractSubscription.java:151)
15:10:30 web.1   |      at com.mongodb.async.client.AbstractSubscription.request(AbstractSubscription.java:84)
15:10:30 web.1   |      at com.mongodb.reactivestreams.client.internal.ObservabletoPublisher$1$1.request(ObservabletoPublisher.java:50)
15:10:30 web.1   |      at kotlinx.coroutines.reactive.SubscriptionChannel.onReceiveEnqueued(Channel.kt:64)
15:10:30 web.1   |      at kotlinx.coroutines.channels.AbstractChannel.enqueueReceive(AbstractChannel.kt:592)
15:10:30 web.1   |      at kotlinx.coroutines.channels.AbstractChannel.access$enqueueReceive(AbstractChannel.kt:488)
15:10:30 web.1   |      at kotlinx.coroutines.channels.AbstractChannel$Itr.hasNextSuspend(AbstractChannel.kt:841)
15:10:30 web.1   |      at kotlinx.coroutines.channels.AbstractChannel$Itr.hasNext(AbstractChannel.kt:827)
15:10:30 web.1   |      at org.litote.kmongo.coroutine.CoroutinePublisherKt.toList(CoroutinePublisher.kt:56)
15:10:30 web.1   |      at org.litote.kmongo.coroutine.CoroutinePublisher.toList(CoroutinePublisher.kt:46)
15:10:30 web.1   |      at com.flockware.BookControllerKt$booksRoutes$1$1.invokeSuspend(BookController.kt:29)
15:10:30 web.1   |      at com.flockware.BookControllerKt$booksRoutes$1$1.invoke(BookController.kt)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)
15:10:30 web.1   |      at io.ktor.features.StatusPages$interceptCall$2.invokeSuspend(StatusPages.kt:102)
15:10:30 web.1   |      at io.ktor.features.StatusPages$interceptCall$2.invoke(StatusPages.kt)
15:10:30 web.1   |      at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)
15:10:30 web.1   |      at kotlinx.coroutines.CoroutinescopeKt.coroutinescope(Coroutinescope.kt:189)
15:10:30 web.1   |      at io.ktor.features.StatusPages.interceptCall(StatusPages.kt:101)
15:10:30 web.1   |      at io.ktor.features.StatusPages$Feature$install$2.invokeSuspend(StatusPages.kt:142)
15:10:30 web.1   |      at io.ktor.features.StatusPages$Feature$install$2.invoke(StatusPages.kt)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:133)
15:10:30 web.1   |      at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
15:10:30 web.1   |      at io.ktor.routing.Routing.executeResult(Routing.kt:151)
15:10:30 web.1   |      at io.ktor.routing.Routing.interceptor(Routing.kt:35)
15:10:30 web.1   |      at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:103)
15:10:30 web.1   |      at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)
15:10:30 web.1   |      at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:110)
15:10:30 web.1   |      at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:133)
15:10:30 web.1   |      at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
15:10:30 web.1   |      at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invokeSuspend(DefaultEnginePipeline.kt:118)
15:10:30 web.1   |      at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)
15:10:30 web.1   |      at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:133)
15:10:30 web.1   |      at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
15:10:30 web.1   |      at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:118)
15:10:30 web.1   |      at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
15:10:30 web.1   |      at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
15:10:30 web.1   |      at kotlinx.coroutines.BuildersKt__Builders_commonKt.startCoroutineImpl(Builders.common.kt:182)
15:10:30 web.1   |      at kotlinx.coroutines.BuildersKt.startCoroutineImpl(UnkNown Source)
15:10:30 web.1   |      at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:145)
15:10:30 web.1   |      at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:54)
15:10:30 web.1   |      at kotlinx.coroutines.BuildersKt.launch(UnkNown Source)
15:10:30 web.1   |      at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:43)
15:10:30 web.1   |      at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:34)
15:10:30 web.1   |      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
15:10:30 web.1   |      at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
15:10:30 web.1   |      at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:370)
15:10:30 web.1   |      at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
15:10:30 web.1   |      at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
15:10:30 web.1   |      at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
15:10:30 web.1   |      at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
15:10:30 web.1   |      at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
15:10:30 web.1   |      at io.ktor.server.netty.EventLoopGroupProxy$Companion$create$factory$1$1.run(NettyApplicationEngine.kt:216)
15:10:30 web.1   |      at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
15:10:30 web.1   |      at java.base/java.lang.Thread.run(Thread.java:832)

我对数据库的连接以这种方式:

KMongo.createClient("mongodb+srv://<username>:<password>@cluster0.euib1.mongodb.net/<dbname>?retryWrites=true&w=majority").coroutine

我的摇篮文件

buildscript {
    repositories {
        jcenter()
    }
    
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
    }
}

apply plugin: 'kotlin'
apply plugin: 'application'

group 'com.example'
version '0.0.1'
mainClassName = 'com.example.ApplicationKt'

apply plugin: 'com.github.johnrengelman.shadow'

shadowJar {
    manifest {
        attributes 'Main-Class': mainClassName
    }
}

sourceSets {
    main.kotlin.srcDirs = main.java.srcDirs = ['src']
    test.kotlin.srcDirs = test.java.srcDirs = ['test']
    main.resources.srcDirs = ['resources']
    test.resources.srcDirs = ['testresources']
}

repositories {
    mavenLocal()
    jcenter()
    maven { url 'https://kotlin.bintray.com/ktor' }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    implementation "io.ktor:ktor-server-netty:$ktor_version"
    implementation "ch.qos.logback:logback-classic:$logback_version"
    implementation "io.ktor:ktor-server-core:$ktor_version"
    implementation "io.ktor:ktor-server-host-common:$ktor_version"
    implementation "io.ktor:ktor-jackson:$ktor_version"
    implementation "io.ktor:ktor-locations:$ktor_version"
    implementation "io.ktor:ktor-metrics:$ktor_version"
    testImplementation "io.ktor:ktor-server-tests:$ktor_version"


    implementation 'org.litote.kmongo:kmongo-coroutine:3.10.0'
    implementation group: 'org.koin',name: 'koin-ktor',version: '2.0.0-beta-1'
    implementation group: 'org.koin',name: 'koin-core-ext',version: '2.0.0-beta-1'
    testImplementation group: 'org.koin',name: 'koin-test',version: '2.0.0-beta-1'
}

这是ApplicationKt.kt:

fun main(args: Array<String>) {
    embeddedServer(Netty,commandLineEnvironment(args)).start(true)
}

@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
    install(CORS) {
        method(HttpMethod.Options)
        method(HttpMethod.Post)
        method(HttpMethod.Put)
        method(HttpMethod.Delete)
        method(HttpMethod.Patch)
        header(HttpHeaders.Authorization)
        header("MyCustomHeader")
        allowCredentials = true
        anyHost() // @Todo: Don't do this in production if possible. Try to limit it.
    }

    install(ContentNegotiation) {
        jackson {
            enable(SerializationFeature.INDENT_OUTPUT)
        }
    }

    install(Locations) {}

    installKoin {
        modules(mongoModule)
    }

    routing {
        
        booksRoutes()

        install(StatusPages) {
            exception<AuthenticationException> { cause ->
                call.respond(HttpStatusCode.Unauthorized)
            }
            exception<AuthorizationException> { cause ->
                call.respond(HttpStatusCode.Forbidden)
            }

        }
    }
}

class AuthenticationException : RuntimeException()
class AuthorizationException : RuntimeException()

和这些路线:

fun Route.booksRoutes() {
    val logger: Logger = LoggerFactory.getLogger("BooksController")
    val client: CoroutineClient by inject()

    route("/books") {
        get("") {
            val books = client.getDatabase(DB_NAME)
                .getCollection<Book>(BOOKS_COLLECTION)
                .find()
                .toList()
            call.respond(HttpStatusCode.OK,books)
        }

        post<Book>("") { request ->
            logger.debug("$request")
            client.getDatabase(DB_NAME)
                    .getCollection<Book>(BOOKS_COLLECTION)
                    .insertOne(request)
            call.respond(HttpStatusCode.OK)
        }

        get("/{bookId}") {
            val bookId:String = call.parameters["bookId"]!!
            val book = client.getDatabase(DB_NAME)
                    .getCollection<Book>(BOOKS_COLLECTION)
                    .findOneById(bookId)
            if (book == null)
                call.respond(HttpStatusCode.NotFound)
            else
                call.respond(HttpStatusCode.OK,book)
        }
    }
}

这是我第一次使用 MongoDB,所以这可能是一个愚蠢的错误。但是,如果这个问题是在我的代码或MongoDB中阿特拉斯配置一个无法理解。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)