Клиент Firestore зависает при попытке прочитать данные, выполняемые в стандарте App Engine с помощью Ktor / Java8

#firebase #google-app-engine #kotlin #google-cloud-firestore #ktor

#firebase #google-app-engine #kotlin #google-облако-firestore #ktor

Вопрос:

У меня возникли проблемы с интеграцией с Firestore в стандартную среду Google App Engine (с использованием Java8, Kotlin и Ktor). Клиент Firestore зависает, когда я пытаюсь выполнить какую-либо операцию. Он отлично работает при запуске на сервере приложений разработчика, но не при запуске в рабочей среде.

Я запускаю:

  • Ktor 1.1.2
  • Kotlin 1.3.21
  • com.google.cloud: google-cloud-firestore (версия 0.81.0-бета)
  • Firestore в собственном режиме

Я тестировал с помощью этого простого маршрута:

 get("/test") {
    try {
        val firestore = FirestoreOptions.getDefaultInstance().service
        val user = firestore.collection("user").document("testusername").get().get()
        call.respond(user.getString("name")!!)
    } catch (ex: Exception) {
        call.respond("Exception: "   ex)
    }
}
  

Посещение /test в веб-браузере приводит к зависанию сайта на минуту, прежде чем возвращается ошибка 500.

В облачной платформе Google зарегистрировано следующее исключение:

 [e~website/20190306t125554.416577836925362605].<stdout>: 2019-03-06 13:01:31.306 [RequestEDA5B9B5] ERROR Application - Unhandled: GET - /test
java.lang.InterruptedException: null
    at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:506)
    at com.google.common.util.concurrent.AbstractFuture$TrustedFuture.get(AbstractFuture.java:83)
    at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture.java:62)
    at com.example.MainApplicationKt$run$4$2.invokeSuspend(MainApplication.kt:93)
    at com.example.MainApplicationKt$run$4$2.invoke(MainApplication.kt)
    at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
    at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
    at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
    at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
    at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:23)
    at io.ktor.routing.Routing.executeResult(Routing.kt:148)
    at io.ktor.routing.Routing.interceptor(Routing.kt:29)
    at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:93)
    at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
    at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
    at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
    at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
    at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:63)
    at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
    at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
    at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
    at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
    at io.ktor.features.CallLogging$Feature$install$2.invokeSuspend(CallLogging.kt:130)
    at io.ktor.features.CallLogging$Feature$install$2.invoke(CallLogging.kt)
    at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
    at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
    at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
    at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
    at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:23)
    at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invokeSuspend(DefaultEnginePipeline.kt:106)
    at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
    at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
    at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
    at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
    at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
    at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:23)
    at io.ktor.server.servlet.KtorServlet$blockingService$1.invokeSuspend(KtorServlet.kt:125)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
    at kotlinx.coroutines.DispatchedKt.resumeCancellable(Dispatched.kt:410)
    at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:25)
    at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:109)
    at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:160)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:52)
    at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    at io.ktor.server.servlet.KtorServlet.blockingService(KtorServlet.kt:96)
    at io.ktor.server.servlet.KtorServlet.service(KtorServlet.kt:57)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:848)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1772)
    at com.google.apphosting.utils.servlet.JdbcMySqlConnectionCleanupFilter.doFilter(JdbcMySqlConnectionCleanupFilter.java:60)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1759)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:582)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
    at com.google.apphosting.runtime.jetty9.ParseBlobUploadHandler.handle(ParseBlobUploadHandler.java:119)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1182)
    at com.google.apphosting.runtime.jetty9.AppEngineWebAppContext.doHandle(AppEngineWebAppContext.java:183)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:512)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1112)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at com.google.apphosting.runtime.jetty9.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:296)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
    at org.eclipse.jetty.server.Server.handle(Server.java:539)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:333)
    at com.google.apphosting.runtime.jetty9.RpcConnection.handle(RpcConnection.java:202)
    at com.google.apphosting.runtime.jetty9.RpcConnector.serviceRequest(RpcConnector.java:81)
    at com.google.apphosting.runtime.jetty9.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:123)
    at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.dispatchServletRequest(JavaRuntime.java:695)
    at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.dispatchRequest(JavaRuntime.java:658)
    at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:628)
    at com.google.apphosting.runtime.JavaRuntime$NullSandboxRequestRunnable.run(JavaRuntime.java:820)
    at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:269)
    at java.lang.Thread.run(Thread.java:748)
  

Вот содержимое моего файла application.conf:

 ktor {
    application {
        modules = [com.example.MainApplicationKt.main]
    }
}
  

Я тестировал:

  • Включение выставления счетов
  • Создание нового проекта с нуля
  • С помощью com.google.firebase: firebase-пакет администратора (версия 6.7.0) вместо этого (с тем же результатом)
  • Вместо этого использую Datastore (который, кажется, работает нормально, но переключение с Firestore потребовало бы, чтобы я переместил весь проект и переписал много кода)

Комментарии:

1. Можете ли вы опубликовать файл application.conf ..?

2. @Moinhan, конечно. Я обновил сообщение содержимым моего файла application.conf.

3. возможно, ваш код выдает исключение… можете ли вы завершить с помощью try catch… и отвечает пустой строкой в предложении catch ..

4. @Moinkhan, я только что попытался перехватить все исключения для тестового кода, но получаю тот же результат, что и раньше.

Ответ №1:

У меня была аналогичная проблема, запущенная в среде App Engine Flex, и в конечном итоге выяснилось, что размер экземпляра по умолчанию, предоставляемый Flex (0,6 ГБ), был слишком мал для поддержки Firestore API. Итак, в случае Flex мне нужно было настроить мой файл app.yaml, чтобы включить раздел «ресурсы» следующим образом:

 resources:
  cpu: 2
  memory_gb: 2.3
  disk_size_gb: 10
  

Ссылка на настройки ресурсов в гибких развертываниях App Engine: https://cloud.google.com/appengine/docs/flexible/custom-runtimes/configuring-your-app-with-app-yaml#resource-settings

Для App Engine Standard я ожидаю, что вам может потребоваться сделать что-то подобное, настроив «instance-class» в вашем app-engine.xml файл. «F1» — это класс экземпляра по умолчанию в App Engine Standard, который имеет ограничение в 128 МБ для среды выполнения Java 8 и 256 МБ для среды выполнения Java 11. Итак, вы можете попробовать перейти к «F2» или «F4».

Ссылка на настройку класса экземпляра в стандартных развертываниях Java App Engine:https://cloud.google.com/appengine/docs/standard/java/config/appref#syntax

Ссылка на классы экземпляров App Engine:https://cloud.google.com/appengine/docs/standard/#instance_classes