Seeking advice on `wire` + `grpc client`. On andro...
# squarelibraries
d
Seeking advice on
wire
+
grpc client
. On android client which uses okhttp as transport, blocking calls work 👌 , but our test streaming call "hangs" and then exits using socket timeout. We can see that server receives the request but then breakpoint which we have set in server code inside a generated grpc method doesn't even hit, so it hangs somewhere inside grpc stuff on server (presumably). Swift client, generated using some Apple library, connects and successfully works with the same streaming call. Any idea on how to debug where to look at would be appreciated.
b
What do you test against? I test against a local fake implementation of my
GrpcStreamingCall
.
d
Our backend dev gave me a jar with the server he wrote using presumably jetty and implementation uses the standard protoc and grpc for java stuff I guess.
on the client I use wire + okhttp
b
Oh I see. And the iOS code hits the same jar?
d
yep. and it works for them, but not for me. we've seen that grpc headers sent by clients are different between iOS/Android, but didn't spot anything major missing (not that we know what to look for :))
b
Hmm sorry I don't have anything in mind
Can you share the client code to see if I can spot anything?
d
Currently it's part of the big project, but I really do only the basic stuff. Gradle config is standard: wire + kotlin block. Client is built like this:
Copy code
val loggingInterceptor = HttpLoggingInterceptor { message -> Timber.tag("OkHttp"); Timber.d(message) }
    loggingInterceptor.level = HTTP_LOG_LEVEL

    val httpClient = OkHttpClient.Builder()
      .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE))
      .connectTimeout(HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
      .readTimeout(HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
      .writeTimeout(HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
      .addNetworkInterceptor(loggingInterceptor)
      .build()

    return GrpcClient.Builder()
      .client(httpClient)
      .baseUrl(baseUrl = "<http://192.168.100.167:8666>")
      .build()
Service itself is build with usual wire's
grpcClient.create()
and then I just call the streaming call and wait for messages in the receiveChannel (launched on the GlobalScope + Dispatchers.IO for testing)
Oh, I also use the latest alpha of wire. I will go and try 3.7.0, just in case
b
Latest alpha is your best bet
4.0.0-alpha.7 I think
d
it was
alpha.6
Oh, ok. will continue poking around than. thanks!
b
Are you setting any certificate? I wonder if that's required for http2 to work
Even in the wire grpc sample we had to set one
d
hmm. we have some mitmproxy certificate for QA which we set in network-security-config for debug builds. apart from that, nothing explicit. also: non-streaming calls do work for some reason on the very same server. but interesting idea, I'll mention this to the backend developer
b
Also when it hangs, there are way to pause the debugger and check which threads are waiting for what but that's not something I'm familiar with.
d
👍 we'll try that too
just in case. server with debug info logging prints this:
Copy code
OUTBOUND SETTINGS: ack=false settings={MAX_CONCURRENT_STREAMS=2147483647, INITIAL_WINDOW_SIZE=1048576, MAX_HEADER_LIST_SIZE=8192}
OUTBOUND WINDOW_UPDATE: streamId=0 windowSizeIncrement=983041
INBOUND SETTINGS: ack=false settings={INITIAL_WINDOW_SIZE=16777216}
OUTBOUND SETTINGS: ack=true
INBOUND WINDOW_UPDATE: streamId=0 windowSizeIncrement=16711681
INBOUND SETTINGS: ack=true
INBOUND HEADERS: streamId=3 headers=GrpcHttp2RequestHeaders[:path: /backend.portfolio.model.PortfolioService/getPortfolioStream, :authority: 192.168.100.167:8666, :method: POST, :scheme: http, te: trailers, grpc-trace-bin: , grpc-accept-encoding: gzip, grpc-encoding: gzip, content-type: application/grpc, accept-encoding: gzip, user-agent: okhttp/4.9.1] padding=0 endStream=false
and then falls silent and no streaming is done For iOS connection after similar exchange (with a bit different headers), streaming works.
hmm... scheme is http, we don't use https currently. not sure why it works for ios though.
b
as far as I know, duplex only works on https. Also, are you sure server is gzip as well? It might be using identity
d
great questions. thank you that's something to check/try!
j
If regular request/response is working I'm gonna guess this bug is related to duplex stuff in OkHttp?
We had an issue in Cash app’s use of streaming that's fixed in that alpha
d
Oh that's inspiring, I'll try to update to the latest alpha and see if it fixes this!
I did try OkHttp-
5.0.0-alpha.2
and the stream still hangs and eventually times out. @jessewilson is there some github issue I can read on this for possible workarounds?
I've also added event listener to OkHttp and I see this log:
Copy code
[34 ms] requestHeadersStart
[41 ms] requestHeadersEnd
[41 ms] requestBodyStart
Setting up flushing for Thread[queued-work-looper,5,main]
[60043 ms] responseFailed: java.net.SocketTimeoutException: timeout
<-- HTTP FAILED: java.net.SocketTimeoutException: timeout
[60045 ms] connectionReleased
[60046 ms] callFailed: java.net.SocketTimeoutException: timeout
b
Jesse is talking about Wire alpha 7
d
oh, oops. Tried it. Sadly it didn't help either, still times out.
I tried native grpc + grpc-kotlin client and the streaming call works with the same server. So it's either a wire bug or my okhttp+wire setup affecting this (in ways I can't figure out). For native lib I had to explicitly say
usePlainText()
when building a transport channel though. In OkHttp I tried to set
ConnectionSpec.CLEARTEXT
too, didn't help
From what I see, wire client sends headers, server receives them and then no body is being received by the server.
225 Views