我有一个Spring Boot应用程序,它试图将消息发布到Cloud Pub / Sub主题。当我在本地计算机上运行应用程序时,它成功地将消息发布到主题中。但是在将其部署到App Engine之后,它失败并出现以下异常
com.google.api.gax.rpc.UnavailableException: io.grpc.StatusRuntimeException: UNAVAILABLE: Credentials failed to obtain metadata
at com.google.api.gax.rpc.ApiExceptionFactory.createException(ApiExceptionFactory.java:69) ~[gax-1.16.0.jar:1.16.0]
at com.google.cloud.pubsub.v1.Publisher$4.onFailure(Publisher.java:373) ~[google-cloud-pubsub-0.33.0-beta.jar:0.33.0-beta]
at com.google.common.util.concurrent.Futures$4.run(Futures.java:1123) [guava-20.0.jar:na]
at com.google.common.util.concurrent.MoreExecutors$DirectExecutor.execute(MoreExecutors.java:435) [guava-20.0.jar:na]
at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:900) [guava-20.0.jar:na]
at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:811) [guava-20.0.jar:na]
at com.google.common.util.concurrent.AbstractFuture.setException(AbstractFuture.java:675) [guava-20.0.jar:na]
at io.grpc.stub.ClientCalls$GrpcFuture.setException(ClientCalls.java:492) [grpc-stub-1.9.0.jar:1.9.0]
at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:467) [grpc-stub-1.9.0.jar:1.9.0]
at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:41) [grpc-core-1.9.0.jar:1.9.0]
at io.grpc.internal.CensusStatsModule$StatsClientInterceptor$1$1.onClose(CensusStatsModule.java:684) [grpc-core-1.9.0.jar:1.9.0]
at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:41) [grpc-core-1.9.0.jar:1.9.0]
at io.grpc.internal.CensusTracingModule$TracingClientInterceptor$1$1.onClose(CensusTracingModule.java:392) [grpc-core-1.9.0.jar:1.9.0]
at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:475) [grpc-core-1.9.0.jar:1.9.0]
at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:63) [grpc-core-1.9.0.jar:1.9.0]
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:557) [grpc-core-1.9.0.jar:1.9.0]
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$600(ClientCallImpl.java:478) [grpc-core-1.9.0.jar:1.9.0]
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:590) [grpc-core-1.9.0.jar:1.9.0]
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) [grpc-core-1.9.0.jar:1.9.0]
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123) [grpc-core-1.9.0.jar:1.9.0]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_112-google-v7]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_112-google-v7]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_112-google-v7]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:295) [na:1.8.0_112-google-v7]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_112-google-v7]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_112-google-v7]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_112-google-v7]
Caused by: io.grpc.StatusRuntimeException: UNAVAILABLE: Credentials failed to obtain metadata
at io.grpc.Status.asRuntimeException(Status.java:526) ~[grpc-core-1.9.0.jar:1.9.0]
... 19 common frames omitted
Caused by: java.io.IOException: Could not get the access token.
at com.google.auth.oauth2.AppEngineCredentials.refreshAccessToken(AppEngineCredentials.java:136) ~[google-auth-library-oauth2-http-0.7.1.jar:na]
at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:149) ~[google-auth-library-oauth2-http-0.7.1.jar:na]
at com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:135) ~[google-auth-library-oauth2-http-0.7.1.jar:na]
at com.google.auth.Credentials.blockingGetToCallback(Credentials.java:103) ~[google-auth-library-credentials-0.9.0.jar:na]
at com.google.auth.Credentials$1.run(Credentials.java:92) ~[google-auth-library-credentials-0.9.0.jar:na]
... 7 common frames omitted
Caused by: java.lang.reflect.InvocationTargetException: null
at sun.reflect.GeneratedMethodAccessor21.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_112-google-v7]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_112-google-v7]
at com.google.auth.oauth2.AppEngineCredentials.refreshAccessToken(AppEngineCredentials.java:131) ~[google-auth-library-oauth2-http-0.7.1.jar:na]
... 11 common frames omitted
Caused by: com.google.apphosting.api.ApiProxy$CallNotFoundException: Can't make API call memcache.Get in a thread that is neither the original request thread nor a thread created by ThreadManager
at com.google.apphosting.api.ApiProxy$CallNotFoundException.foreignThread(ApiProxy.java:844) ~[runtime-shared.jar:na]
at com.google.apphosting.api.ApiProxy$1.get(ApiProxy.java:183) ~[runtime-shared.jar:na]
at com.google.apphosting.api.ApiProxy$1.get(ApiProxy.java:180) ~[runtime-shared.jar:na]
at com.google.appengine.api.utils.FutureWrapper.get(FutureWrapper.java:93) ~[appengine-api.jar:na]
at com.google.appengine.api.memcache.MemcacheServiceImpl.quietGet(MemcacheServiceImpl.java:28) ~[appengine-api.jar:na]
at com.google.appengine.api.memcache.MemcacheServiceImpl.get(MemcacheServiceImpl.java:51) ~[appengine-api.jar:na]
at com.google.appengine.api.appidentity.AppIdentityServiceImpl.getAccessToken(AppIdentityServiceImpl.java:302) ~[appengine-api.jar:na]
... 15 common frames omitted
代码是从this Spring guide复制的。
答案 0 :(得分:2)
您共享的错误消息明确指出UNAVAILABLE: Credentials failed to obtain metadata
,因此看起来该错误与App Engine中的凭据有关。显然,根据您对问题的描述,您的应用程序在本地开发服务器中运行时工作正常,但是一旦将其部署到App Engine Standard应用程序,它就会失败。这一切都表明您可能有错误的凭据配置。
如the Authentication section in the guide you shared和App Engine's documentation中所述,App Engine Standard使用应用程序默认凭据进行身份验证。为此,它会检查环境变量GOOGLE_APPLICATION_CREDENTIALS
中的凭据,如果缺少这些凭据,它将使用App Engine应用程序中的默认服务帐户。
知道这一点,您可能遇到的问题是您指向远程(App Engine)环境中不可用的凭据文件。因此,我的建议是,如果您认为可以使用默认的App Engine服务帐户,则只需将GOOGLE_APPLICATION_CREDENTIALS
环境变量和spring.cloud.gcp.credentials.location
属性保留为空,以便App Engine从中获取默认凭据自己的服务帐户。请记住,它应该具有与Pub / Sub交互的权限,以便它也可以工作,因此如果需要,您可能必须grant roles to the service account。