Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PubSub: NullPointerException at com.google.apphosting.runtime.ApiProxyImpl$CurrentRequestThreadFactory.newThread(ApiProxyImpl.java:1267) #2275

Closed
jbaldassari opened this issue Jul 26, 2017 · 31 comments
Assignees
Labels
api: pubsub Issues related to the Pub/Sub API. priority: p1 Important issue which blocks shipping the next release. Will be fixed prior to next release. running on app engine type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.

Comments

@jbaldassari
Copy link

jbaldassari commented Jul 26, 2017

After upgrading my PubSub client to 0.20.3-beta (as well as a few other Google dependencies) and switching from the Java8 flexible environment to the Java8 standard environment I'm no longer able to publish messages to my PubSub topic. I'm seeing this error in the logs for my AppEngine standard Java8 environment after publishing a message and get()ing the Future:

io.grpc.internal.ChannelExecutor drain: Runnable threw exception in ChannelExecutor (ChannelExecutor.java:89)
java.lang.NullPointerException
	at com.google.apphosting.runtime.ApiProxyImpl$CurrentRequestThreadFactory.newThread(ApiProxyImpl.java:1267)
	at com.google.common.util.concurrent.ThreadFactoryBuilder$1.newThread(ThreadFactoryBuilder.java:162)
	at java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor.java:612)
	at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:925)
	at java.util.concurrent.ThreadPoolExecutor.ensurePrestart(ThreadPoolExecutor.java:1587)
	at java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:336)
	at java.util.concurrent.ScheduledThreadPoolExecutor.schedule(ScheduledThreadPoolExecutor.java:555)
	at io.grpc.internal.ManagedChannelImpl.rescheduleIdleTimer(ManagedChannelImpl.java:334)
	at io.grpc.internal.ManagedChannelImpl.exitIdleMode(ManagedChannelImpl.java:299)
	at io.grpc.internal.ManagedChannelImpl$4$1.run(ManagedChannelImpl.java:357)
	at io.grpc.internal.ChannelExecutor.drain(ChannelExecutor.java:87)
	at io.grpc.internal.ManagedChannelImpl$4.get(ManagedChannelImpl.java:359)
	at io.grpc.internal.ClientCallImpl.start(ClientCallImpl.java:218)
	at io.grpc.ForwardingClientCall.start(ForwardingClientCall.java:47)
	at com.google.api.gax.grpc.HeaderInterceptor$1.start(HeaderInterceptor.java:62)
	at io.grpc.stub.ClientCalls.startCall(ClientCalls.java:276)
	at io.grpc.stub.ClientCalls.asyncUnaryRequestCall(ClientCalls.java:252)
	at io.grpc.stub.ClientCalls.futureUnaryCall(ClientCalls.java:186)
	at com.google.pubsub.v1.PublisherGrpc$PublisherFutureStub.publish(PublisherGrpc.java:460)
	at com.google.cloud.pubsub.v1.Publisher.publishOutstandingBatch(Publisher.java:329)
	at com.google.cloud.pubsub.v1.Publisher.publishAllOutstanding(Publisher.java:304)
	at com.google.cloud.pubsub.v1.Publisher.access$500(Publisher.java:79)
	at com.google.cloud.pubsub.v1.Publisher$5.run(Publisher.java:283)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:295)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

I'm using a Gradle build with the following relevant dependencies:

dependencies {
  providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
  providedCompile 'com.google.appengine:appengine:+'
  testCompile 'org.eclipse.jetty:jetty-server:9.+'
  testCompile 'org.eclipse.jetty:jetty-servlet:9.+'
  compile group: 'com.google.guava', name: 'guava', version: '19.+'
  compile group: 'com.google.inject', name: 'guice', version: '4.+'
  compile 'com.google.appengine:appengine-api-1.0-sdk:1.+'
  compile 'com.google.cloud:google-cloud-storage:1.2+'
  compile group: 'com.google.cloud', name: 'google-cloud-pubsub', version: '0.20+'
  compile ('com.google.cloud:google-cloud-datastore:1.2+')
  compile('com.google.apis:google-api-services-cloudkms:v1-rev15-1.22.0') {
     exclude(group: 'com.google.guava', module: 'guava-jdk5')
  }
  compile(group: 'com.google.api-client', name: 'google-api-client', version: '1.+') {
     exclude(group: 'com.google.guava', module: 'guava-jdk5')
  }
  compile(group: 'com.google.api-client', name: 'google-api-client-appengine', version: '1.+') {
     exclude(group: 'com.google.guava', module: 'guava-jdk5')
  }
}

The deployment environment is AppEngine standard java8. I haven't been able to find the source code for ApiProxyImpl.java anywhere, so I'm unable to do much more debugging here. I guess I'll try downgrading the dependency and hope it works.

@jbaldassari
Copy link
Author

After rolling back to the 0.11 dependencies I'm now getting an error about not being able to authenticate. This may be due to differences between the flex and standard java8 environments because I never had this issue in the flex environment:

Caused by: java.util.concurrent.ExecutionException: io.grpc.StatusRuntimeException: UNAUTHENTICATED
	at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:500) ~[guava-20.0.jar:na]
	at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:401) ~[guava-20.0.jar:na]
	at com.google.api.gax.core.AbstractApiFuture.get(AbstractApiFuture.java:60) ~[gax-0.8.0.jar:na]
	at io.longreen.api.v1.service.ExecutionServiceImpl.createRunPolicyExecution(ExecutionServiceImpl.java:163) ~[classes/:na]
	... 84 common frames omitted
Caused by: io.grpc.StatusRuntimeException: UNAUTHENTICATED
	at io.grpc.Status.asRuntimeException(Status.java:545) ~[grpc-core-1.0.3.jar:1.0.3]
	at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:442) ~[grpc-stub-1.0.3.jar:1.0.3]
	at io.grpc.ClientInterceptors$CheckedForwardingClientCall.start(ClientInterceptors.java:203) ~[grpc-core-1.0.3.jar:1.0.3]
	at io.grpc.ForwardingClientCall.start(ForwardingClientCall.java:47) ~[grpc-core-1.0.3.jar:1.0.3]
	at com.google.api.gax.grpc.HeaderInterceptor$1.start(HeaderInterceptor.java:62) ~[gax-0.8.0.jar:na]
	at io.grpc.stub.ClientCalls.startCall(ClientCalls.java:273) ~[grpc-stub-1.0.3.jar:1.0.3]
	at io.grpc.stub.ClientCalls.asyncUnaryRequestCall(ClientCalls.java:252) ~[grpc-stub-1.0.3.jar:1.0.3]
	at io.grpc.stub.ClientCalls.futureUnaryCall(ClientCalls.java:189) ~[grpc-stub-1.0.3.jar:1.0.3]
	at com.google.pubsub.v1.PublisherGrpc$PublisherFutureStub.publish(PublisherGrpc.java:460) ~[grpc-google-cloud-pubsub-v1-0.1.6.jar:na]
	at com.google.cloud.pubsub.spi.v1.Publisher.publishOutstandingBatch(Publisher.java:333) ~[google-cloud-pubsub-0.11.2-alpha.jar:0.11.2-alpha]
	at com.google.cloud.pubsub.spi.v1.Publisher.publishAllOutstanding(Publisher.java:312) ~[google-cloud-pubsub-0.11.2-alpha.jar:0.11.2-alpha]
	at com.google.cloud.pubsub.spi.v1.Publisher.access$500(Publisher.java:76) ~[google-cloud-pubsub-0.11.2-alpha.jar:0.11.2-alpha]
	at com.google.cloud.pubsub.spi.v1.Publisher$5.run(Publisher.java:291) ~[google-cloud-pubsub-0.11.2-alpha.jar:0.11.2-alpha]
	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]
	... 1 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.6.0.jar:na]
	at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:149) ~[google-auth-library-oauth2-http-0.6.0.jar:na]
	at com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:135) ~[google-auth-library-oauth2-http-0.6.0.jar:na]
	at io.grpc.auth.ClientAuthInterceptor.getRequestMetadata(ClientAuthInterceptor.java:150) ~[grpc-auth-1.0.3.jar:1.0.3]
	at io.grpc.auth.ClientAuthInterceptor.access$100(ClientAuthInterceptor.java:64) ~[grpc-auth-1.0.3.jar:1.0.3]
	at io.grpc.auth.ClientAuthInterceptor$1.checkedStart(ClientAuthInterceptor.java:96) ~[grpc-auth-1.0.3.jar:1.0.3]
	at io.grpc.ClientInterceptors$CheckedForwardingClientCall.start(ClientInterceptors.java:195) ~[grpc-core-1.0.3.jar:1.0.3]
	... 17 common frames omitted
Caused by: java.lang.reflect.InvocationTargetException: null
	at sun.reflect.GeneratedMethodAccessor60.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.6.0.jar:na]
	... 23 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:300) ~[appengine-api.jar:na]
	... 27 common frames omitted

@jbaldassari
Copy link
Author

In the end I wasn't able to find a workaround, so I had to revert all my recent changes. In a separate test environment (Java 8 standard) I noticed a few other errors that may be relevant in addition to the original NullPointerException:

[s~mabl-prod-app/a2fd9e3b8f46288bf720544cdf894dac6fb55fbb.402925994294374259].<stdout>: [WARN] io.netty.util.NetUtil - Failed to find the loopback interface
[s~mabl-prod-app/a2fd9e3b8f46288bf720544cdf894dac6fb55fbb.402925994294374259].<stdout>: [WARN] io.netty.util.internal.MacAddressUtil - Failed to find a usable hardware address from the network interfaces; using random bytes: 4e:c1:f4:65:a3:40:fe:91
[s~mabl-prod-app/a2fd9e3b8f46288bf720544cdf894dac6fb55fbb.402925994294374259].<stdout>: [WARN] io.netty.util.NetUtil - Failed to retrieve the list of available network interfaces
java.net.SocketException: Inappropriate ioctl for device
	at java.net.NetworkInterface.getAll(Native Method) ~[na:1.8.0_112-google-v7]
	at java.net.NetworkInterface.getNetworkInterfaces(NetworkInterface.java:343) ~[na:1.8.0_112-google-v7]
	at io.netty.util.NetUtil.<clinit>(NetUtil.java:171) ~[netty-common-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.util.internal.MacAddressUtil.bestAvailableMac(MacAddressUtil.java:50) [netty-common-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.util.internal.MacAddressUtil.defaultMachineId(MacAddressUtil.java:138) [netty-common-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.DefaultChannelId.<clinit>(DefaultChannelId.java:99) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.AbstractChannel.newId(AbstractChannel.java:107) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.AbstractChannel.<init>(AbstractChannel.java:79) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.nio.AbstractNioChannel.<init>(AbstractNioChannel.java:84) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.nio.AbstractNioByteChannel.<init>(AbstractNioByteChannel.java:55) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.socket.nio.NioSocketChannel.<init>(NioSocketChannel.java:98) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.socket.nio.NioSocketChannel.<init>(NioSocketChannel.java:88) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.socket.nio.NioSocketChannel.<init>(NioSocketChannel.java:81) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.socket.nio.NioSocketChannel.<init>(NioSocketChannel.java:74) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) [na:1.8.0_112-google-v7]
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) [na:1.8.0_112-google-v7]
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) [na:1.8.0_112-google-v7]
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423) [na:1.8.0_112-google-v7]
	at java.lang.Class.newInstance(Class.java:443) [na:1.8.0_112-google-v7]
	at io.netty.channel.ReflectiveChannelFactory.newChannel(ReflectiveChannelFactory.java:38) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.bootstrap.AbstractBootstrap.initAndRegister(AbstractBootstrap.java:321) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.bootstrap.AbstractBootstrap.register(AbstractBootstrap.java:235) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.grpc.netty.NettyClientTransport.start(NettyClientTransport.java:215) [grpc-netty-1.4.0.jar:1.4.0]
	at io.grpc.internal.ForwardingConnectionClientTransport.start(ForwardingConnectionClientTransport.java:44) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.InternalSubchannel.startNewTransport(InternalSubchannel.java:217) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.InternalSubchannel.obtainActiveTransport(InternalSubchannel.java:190) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ManagedChannelImpl$SubchannelImplImpl.obtainActiveTransport(ManagedChannelImpl.java:827) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.GrpcUtil.getTransportFromPickResult(GrpcUtil.java:592) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.DelayedClientTransport.reprocess(DelayedClientTransport.java:295) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ManagedChannelImpl$LbHelperImpl$5.run(ManagedChannelImpl.java:733) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ChannelExecutor.drain(ChannelExecutor.java:87) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ManagedChannelImpl$LbHelperImpl.runSerialized(ManagedChannelImpl.java:724) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ManagedChannelImpl$NameResolverListenerImpl.onAddresses(ManagedChannelImpl.java:773) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.DnsNameResolver$1.run(DnsNameResolver.java:191) [grpc-core-1.4.0.jar:1.4.0]
	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]
[s~mabl-prod-app/a2fd9e3b8f46288bf720544cdf894dac6fb55fbb.402925994294374259].<stdout>: [WARN] io.netty.util.internal.MacAddressUtil - Failed to retrieve the list of available network interfaces
java.net.SocketException: Inappropriate ioctl for device
	at java.net.NetworkInterface.getAll(Native Method) ~[na:1.8.0_112-google-v7]
	at java.net.NetworkInterface.getNetworkInterfaces(NetworkInterface.java:343) ~[na:1.8.0_112-google-v7]
	at io.netty.util.internal.MacAddressUtil.bestAvailableMac(MacAddressUtil.java:55) [netty-common-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.util.internal.MacAddressUtil.defaultMachineId(MacAddressUtil.java:138) [netty-common-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.DefaultChannelId.<clinit>(DefaultChannelId.java:99) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.AbstractChannel.newId(AbstractChannel.java:107) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.AbstractChannel.<init>(AbstractChannel.java:79) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.nio.AbstractNioChannel.<init>(AbstractNioChannel.java:84) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.nio.AbstractNioByteChannel.<init>(AbstractNioByteChannel.java:55) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.socket.nio.NioSocketChannel.<init>(NioSocketChannel.java:98) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.socket.nio.NioSocketChannel.<init>(NioSocketChannel.java:88) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.socket.nio.NioSocketChannel.<init>(NioSocketChannel.java:81) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.channel.socket.nio.NioSocketChannel.<init>(NioSocketChannel.java:74) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) [na:1.8.0_112-google-v7]
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) [na:1.8.0_112-google-v7]
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) [na:1.8.0_112-google-v7]
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423) [na:1.8.0_112-google-v7]
	at java.lang.Class.newInstance(Class.java:443) [na:1.8.0_112-google-v7]
	at io.netty.channel.ReflectiveChannelFactory.newChannel(ReflectiveChannelFactory.java:38) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.bootstrap.AbstractBootstrap.initAndRegister(AbstractBootstrap.java:321) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.netty.bootstrap.AbstractBootstrap.register(AbstractBootstrap.java:235) [netty-transport-4.1.11.Final.jar:4.1.11.Final]
	at io.grpc.netty.NettyClientTransport.start(NettyClientTransport.java:215) [grpc-netty-1.4.0.jar:1.4.0]
	at io.grpc.internal.ForwardingConnectionClientTransport.start(ForwardingConnectionClientTransport.java:44) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.InternalSubchannel.startNewTransport(InternalSubchannel.java:217) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.InternalSubchannel.obtainActiveTransport(InternalSubchannel.java:190) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ManagedChannelImpl$SubchannelImplImpl.obtainActiveTransport(ManagedChannelImpl.java:827) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.GrpcUtil.getTransportFromPickResult(GrpcUtil.java:592) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.DelayedClientTransport.reprocess(DelayedClientTransport.java:295) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ManagedChannelImpl$LbHelperImpl$5.run(ManagedChannelImpl.java:733) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ChannelExecutor.drain(ChannelExecutor.java:87) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ManagedChannelImpl$LbHelperImpl.runSerialized(ManagedChannelImpl.java:724) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ManagedChannelImpl$NameResolverListenerImpl.onAddresses(ManagedChannelImpl.java:773) [grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.DnsNameResolver$1.run(DnsNameResolver.java:191) [grpc-core-1.4.0.jar:1.4.0]
	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]
io.grpc.internal.ChannelExecutor drain: Runnable threw exception in ChannelExecutor (ChannelExecutor.java:89)
java.lang.NullPointerException
	at com.google.apphosting.runtime.ApiProxyImpl$CurrentRequestThreadFactory.newThread(ApiProxyImpl.java:1267)
	at com.google.common.util.concurrent.ThreadFactoryBuilder$1.newThread(ThreadFactoryBuilder.java:162)
	at java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor.java:612)
	at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:925)
	at java.util.concurrent.ThreadPoolExecutor.ensurePrestart(ThreadPoolExecutor.java:1587)
	at java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:336)
	at java.util.concurrent.ScheduledThreadPoolExecutor.schedule(ScheduledThreadPoolExecutor.java:555)
	at io.grpc.internal.ManagedChannelImpl.rescheduleIdleTimer(ManagedChannelImpl.java:334)
	at io.grpc.internal.ManagedChannelImpl.access$700(ManagedChannelImpl.java:83)
	at io.grpc.internal.ManagedChannelImpl$2.handleNotInUse(ManagedChannelImpl.java:247)
	at io.grpc.internal.InUseStateAggregator.updateObjectInUse(InUseStateAggregator.java:60)
	at io.grpc.internal.ManagedChannelImpl$1.transportInUse(ManagedChannelImpl.java:198)
	at io.grpc.internal.DelayedClientTransport$2.run(DelayedClientTransport.java:116)
	at io.grpc.internal.ChannelExecutor.drain(ChannelExecutor.java:87)
	at io.grpc.internal.InternalSubchannel$TransportListener.transportReady(InternalSubchannel.java:458)
	at io.grpc.netty.ClientTransportLifecycleManager.notifyReady(ClientTransportLifecycleManager.java:58)
	at io.grpc.netty.NettyClientHandler$FrameListener.onSettingsRead(NettyClientHandler.java:646)
	at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder$FrameReadListener.onSettingsRead(DefaultHttp2ConnectionDecoder.java:412)
	at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder$PrefaceFrameListener.onSettingsRead(DefaultHttp2ConnectionDecoder.java:624)
	at io.netty.handler.codec.http2.Http2InboundFrameLogger$1.onSettingsRead(Http2InboundFrameLogger.java:93)
	at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readSettingsFrame(DefaultHttp2FrameReader.java:542)
	at io.netty.handler.codec.http2.DefaultHttp2FrameReader.processPayloadState(DefaultHttp2FrameReader.java:263)
	at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readFrame(DefaultHttp2FrameReader.java:160)
	at io.netty.handler.codec.http2.Http2InboundFrameLogger.readFrame(Http2InboundFrameLogger.java:41)
	at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder.decodeFrame(DefaultHttp2ConnectionDecoder.java:116)
	at io.netty.handler.codec.http2.Http2ConnectionHandler$FrameDecoder.decode(Http2ConnectionHandler.java:353)
	at io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.decode(Http2ConnectionHandler.java:224)
	at io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:413)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1267)
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1078)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
	at java.lang.Thread.run(Thread.java:745)

@jbaldassari
Copy link
Author

@jbaldassari
Copy link
Author

Found a mention of a similar problem here:

https://groups.google.com/d/msg/google-appengine/2UTg4Eqskyk/PbqYEK3GAAAJ

I tried the work-around suggested there (https://gist.github.com/cmaan/7752e3c4fd0b1ba90a745cb6db232206) and the NPE has stopped happening. But now I'm back to the other UNAUTHENTICATED error:

Caused by: io.grpc.StatusRuntimeException: UNAUTHENTICATED
	at io.grpc.Status.asRuntimeException(Status.java:543) ~[grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:442) ~[grpc-stub-1.4.0.jar:1.4.0]
	at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:426) ~[grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:76) ~[grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:512) ~[grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$700(ClientCallImpl.java:429) ~[grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:544) ~[grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:52) ~[grpc-core-1.4.0.jar:1.4.0]
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:117) ~[grpc-core-1.4.0.jar:1.4.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]
	... 1 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.0.jar:na]
	at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:149) ~[google-auth-library-oauth2-http-0.7.0.jar:na]
	at com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:135) ~[google-auth-library-oauth2-http-0.7.0.jar:na]
	at io.grpc.auth.GoogleAuthLibraryCallCredentials$1.run(GoogleAuthLibraryCallCredentials.java:110) ~[grpc-auth-1.4.0.jar:1.4.0]
	... 7 common frames omitted
Caused by: java.lang.reflect.InvocationTargetException: null
	at sun.reflect.GeneratedMethodAccessor60.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.0.jar:na]
	... 10 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:300) ~[appengine-api.jar:na]
	... 14 common frames omitted

@cmaan
Copy link

cmaan commented Jul 26, 2017

I see you found my crazy workaround in https://gist.github.com/cmaan/7752e3c4fd0b1ba90a745cb6db232206

We stumbled upon the same UNAUTHENTICATED issues, as the automagic GAE authentication does not work anymore in a plain java thread pool. To deal with those, you can use a PubSub client with explicit credentials, e.g.:

Publisher.defaultBuilder(topicName)
	.setCredentialsProvider(/* ... */)
	.build()

This way, we got Spanner and PubSub to work on java8.

@jbaldassari
Copy link
Author

jbaldassari commented Jul 26, 2017

Thanks for the tip, @cmaan. I'm still having some trouble getting it working, though. What credentials provider did you use? Did you have to pass it in a file?

What I tried to do was to get the default credentials from AppEngine before applying the work-around, kind of like this:

private static final Credentials defaultPubSubCredentials;
static {
    defaultPubSubCredentials = TopicAdminSettings.defaultCredentialsProviderBuilder().build().getCredentials();
    GrpcUtilPatchThreadFactories.patch();
}

...
final Publisher publisher = Publisher.defaultBuilder(topicName)
    .setCredentialsProvider(new CredentialsProvider() {
        @Override
        public Credentials getCredentials() throws IOException {
            return defaultPubSubCredentials;
        }
    }).build();

That didn't seem to work, though. I'm still getting the same UNAUTHENTICATED error with the message about not being able to call memcache.Get from that thread.

Maybe I'll have to put some service account credentials in a file in GCS and then load them in from there?

@kir-titievsky
Copy link

@garrettjonesgoogle @pongad Do you two see any reason why this might happen?

@jbaldassari
Copy link
Author

jbaldassari commented Jul 26, 2017

The issues discussed in these tickets seem relevant:

#1807
#1918
#2144

@neozwu
Copy link
Contributor

neozwu commented Jul 27, 2017

@jbaldassari One possible workaround is to use executor for Pub/Sub, as mentioned in #2150 . I think when gRPC request is initiated through executor (i.e., not in request thread), GrpcUtils will pick the right threadFactory. My guess is right now it picks requestThreadFactory, and new threads generated by this factory will be scoped to the request. So it will throw NPE.

@cmaan
Copy link

cmaan commented Jul 27, 2017

@jbaldassari

Maybe I'll have to put some service account credentials in a file in GCS and then load them in from there?

There might be a better way, but that's exactly what we currently do

@jbaldassari
Copy link
Author

jbaldassari commented Jul 27, 2017

@neozwu I tried the workaround suggested in #2150, but I'm still getting the same NPE at ApiProxyImpl.java:1267. Specifically I'm now doing this:

private static final ExecutorService executor = 
    Executors.newCachedThreadPool(new ThreadFactoryBuilder()
        .setThreadFactory(Executors.defaultThreadFactory()).setDaemon(true)
            .setNameFormat("PubSubQueuePublisher-%d").build());
// ...
final PubsubMessage pubsubMessage = // ...
executor.submit(() -> publisher.publish(pubsubMessage));

Am I supposed to be using a normal Java ExecutorService here, or is there some special way that I need to construct it?

I wonder if I also need to construct the PubSubQueuePublisher instance within a thread created by ExecutorService. That seems like it would be wasteful to construct a new PubSubQueuePublisher every time, but maybe I'll try it to see if it makes any difference.

@jbaldassari
Copy link
Author

jbaldassari commented Jul 27, 2017

Update on workaround testing:

  • Publish message in thread created by normal Java Executorservice: NPE at ApiProxyImpl.java:1267
  • Create PubSubQueuePublisher and publish message inside thread created by ExecutorService: No NPE, but it still doesn't work because the AppEngine automatic authentication stuff doesn't work, and I just get an UNAUTHENTICATED error

@jbaldassari
Copy link
Author

jbaldassari commented Jul 27, 2017

I just tried another workaround which got me past both the ApiProxyImpl:1267 NPE and the UNAUTHENTICATED error! What I did was to first obtain App Engine credentials from within an AppEngine request thread, and then I passed those credentials into a ExecutorService thread to perform the actual RPC. The trick was to force the credentials to be retrieved immediately in the request thread via a refresh() call. If this is not done then they will be retrieved when they are used inside the executor thread, and it will blow up with the unauthenticated error. Obtaining the credentials in the App Engine request thread works fine.

Here's what the code looks like:

final Credentials pubSubCredentials = TopicAdminSettings.defaultCredentialsProviderBuilder().build().getCredentials();
pubSubCredentials.refresh();    // Force immediate retrieval of credentials from within request thread so that AppEngine automatic authentication works
executor.submit(() -> {
    final Publisher publisher = Publisher.defaultBuilder(topic)
         .setCredentialsProvider(FixedCredentialsProvider.create(pubSubCredentials))
         .build();
    try {
        return publisher.publish(pubsubMessage);
    } finally {
        publisher.shutdown();
    }
});

Update:
Initially I was getting a PERMISSION_DENIED error here, but it turns out that it was a legitimate issue because I was publishing across projects. Once I configured the permissions for Project A to publish to a topic in Project B it all worked. This still is not an ideal solution because it's not efficient to get the credentials every time and create/destroy the Publisher every time, but at least it works for now. I think it would be possible to kick off a background task to cache and refresh the credentials (and Publisher?), so that might be a little bit better than creating it every time.

@neozwu neozwu assigned neozwu and unassigned neozwu Jul 27, 2017
@tcoffee-google tcoffee-google added api: pubsub Issues related to the Pub/Sub API. priority: p1 Important issue which blocks shipping the next release. Will be fixed prior to next release. running on app engine type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns. labels Jul 28, 2017
@tcoffee-google
Copy link
Contributor

@rrch per your #1752 (comment), is there any update on thread execution in GAE standard?

@neozwu
Copy link
Contributor

neozwu commented Jul 28, 2017

In grpc, it seems it returns currentRequestThreadFactory (link), which is from guava. But maybe backendThreadFactory should be returned instead ?
/cc @ejona86 @ludoch

@cmaan
Copy link

cmaan commented Jul 28, 2017

@neozwu It seems some shared grpc thread factories are actually decided by classloading side effects. I guess that's the reason why this demo [1] works on GAE j8, while almost every other realistic setup won't.
To replicate the classloading effect on static globals (similar to GrpcUtil.SHARED_CHANNEL_EXECUTOR), I've created a small toy project [2].

Regarding backgroundThreadFactory, this would make it impossible to use grpc with automatic scaling, right?

[1] https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/appengine-java8/spanner
[2] https://github.com/cmaan/threadfactory/

@neozwu
Copy link
Contributor

neozwu commented Jul 31, 2017

@cmaan thank you for your investigation, and your demo project. Let me summarize what I understand, and please feel free to correct me. So it seems

(1) when a Grpc call is initiated in an appengine request, the underlying grpc library will pick up currentRequestThreadFactory (by consulting the guava code) for its threading facilities, as demonstrated in your toy project. This could potentially cause a problem. Although I'm not exactly sure what the problem is. These Grpc threads created by currentRequestThreadFactory cannot outlive the request, but in #2150 sample code, the request thread is clearly blocked waiting for Grpc to complete. Maybe appengine request thread times out ?

(2) But if the Grpc call is in a default background thread (by, for example, using executorService in appengine request), the underlying guava code will fail to invoke appengine api (even though the sys prop is set) due to appengine restrictions, and thus will use defaultThreadFactory, therefore Grpc will get defaultThreadFactory.

@jbaldassari would you mind sharing some sample code, to help further investigating this issue?

@jbaldassari
Copy link
Author

jbaldassari commented Jul 31, 2017

@neozwu sure, I can give you a couple of examples. First, some context. We have an interface called QueuePublisher with two implementations: InMemoryQueuePublisher and PubSubQueuePublisher. For local testing we use InMemoryQueuePublisher which is backed by a simple Java blocking queue, and for deploying to AppEngine we use PubSubQueuePublisher. The implementation is injected dynamically using Guice when the servlets are initialized. So the PubSubQueuePublisher constructor is called at servlet initialization time via Guice, and the publish(QueueMessage) method is called when servicing a request, presumably from an AppEngine request thread.

The following implementation does not work and results in NPE @ ApiProxyImpl.java:1267 : https://gist.github.com/jbaldassari/cf1160c7ef9207e6ddd562dc2a1951db
In the above example the PubSub Publisher is passed into the constructor, so it's being created/initialized by Guice here. I don't think that really matters because the problem seems to be related to fetching credentials the first time they are needed, but I thought I'd mention it anyway.

Here's another example that does not work, but for a different reason. Here we're creating the Publisher in an ExecutorService thread. In this case we get an UNAUTHENTICATED error when trying to retrieve the credentials, apparently because we're not in an AppEngine request thread: https://gist.github.com/jbaldassari/566f1f52e5406e72508c71fddfc515ef

Finally, a working example: https://gist.github.com/jbaldassari/3f9a93e8e956f16f5bad5d658d204e4c

Here we're retrieving the credentials from the AppEngine request thread but creating the Publisher and publishing the message from an ExecutorService thread.

Hopefully these examples help. The key seems to be that in order for authentication to work the credentials must be retrieved from an AppEngine request thread, but in order to avoid the NPE the Publisher has to be created (or at least invoked?) from a normal Java thread. If you need working and non-working examples with complete projects I can probably put something together this week, but it will take more time to create it and test it.

@lesv
Copy link
Contributor

lesv commented Jul 31, 2017

Take a look at https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/appengine-java8/gaeinfo (enable TOKEN) and you can get a token using the Metadata server from any thread.

@ejona86
Copy link

ejona86 commented Jul 31, 2017

In gRPC, IS_RESTRICTED_APPENGINE == false on GAE Java 8.

@neozwu
Copy link
Contributor

neozwu commented Aug 1, 2017

@ejona86 I'm not very familiar with gRPC codebase, but it seems to me regardless of IS_RESTRICTED_APPENGINE, the threadFactory will always be currentRequestThreadFactory when running in a request thread on GAE J7, or J8 .

@ejona86
Copy link

ejona86 commented Aug 1, 2017

@neozwu, ah, you're right. However, IS_RESTRICTED_APPENGINE other behavior. gRPC assumes it can have background threads when not restricted and so it shares threads across requests.

@neozwu
Copy link
Contributor

neozwu commented Aug 1, 2017

@ejona86 Yes, the restricted behavior for request threads makes sense. However, "AppEngine must immediately release shared resources, particularly executors which could retain request-scoped threads which become zombies after the request completes" applies to both GAE J7 and J8. Why IS_RESTRICTED_APPENGINE only checks for J7 ?

@ejona86
Copy link

ejona86 commented Aug 1, 2017

@neozwu, because GAE Java 8 didn't have that restriction. If it has that restriction, then at some point that changed. At the very least, we know it isn't as restricted as J7 because in J8 you can load binaries where in J7 you couldn't. Is there some documentation that describes the current limitations across all the GAE varieties?

@neozwu
Copy link
Contributor

neozwu commented Aug 1, 2017

@ejona86 : confirmed with @ifigotin offline, on GAE J8, threads created by currentRequestThreadFactory still cannot outlive the request. This behavior is the same on J7 & J8. So I think at least here the IS_RESTRICTED_APPENGINE part should apply to both J7 & J8 (not sure about other cases within grpc that rely on this flag).

/cc @ifigotin @ludoch @eamonnmcmanus

@lesv
Copy link
Contributor

lesv commented Aug 1, 2017

But if you create them as a normal java thread, they will. (at least on Java 8)

@neozwu
Copy link
Contributor

neozwu commented Aug 1, 2017

@lesv exactly, I think that's why using ExectuorService will work - a normal java thread cannot access appengine api, so the underlying guava code thinks it's not on appengine, and dispatches to gRPC a defaultThreadFactory, which creates threads that outlive request's lifecycle.

@lesv
Copy link
Contributor

lesv commented Aug 1, 2017

Why not use normal threads, and use the metadata server to get tokens? The ExecutorService really looks bad and isn't easy.

@garrettjonesgoogle
Copy link
Member

@ejona86 , we need some kind of resolution for thread treatment by grpc in GAE J8.

@ludoch
Copy link
Contributor

ludoch commented Sep 20, 2017

Should work with latest pub sub library.
Reopen if you still see it with updated libs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: pubsub Issues related to the Pub/Sub API. priority: p1 Important issue which blocks shipping the next release. Will be fixed prior to next release. running on app engine type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Projects
None yet
Development

No branches or pull requests

9 participants