简体   繁体   English

如何使具有服务器流连接的 Android grpc 客户端保持活动状态?

[英]How to keep an Android grpc client with server streaming connection alive?

I have a grpc-js server and a Kotlin for Android client that makes a server streaming call.我有一个 grpc-js 服务器和一个 Kotlin 用于 Android 客户端,可以进行服务器流式调用。 This is the GRPCService class.这是 GRPCService class。

class GRPCService {
    private val mChannel = ManagedChannelBuilder
        .forAddress(GRPC_HOST_ADDRESS, GRPC_HOST_PORT)
        .usePlaintext()
        .keepAliveTime(10, TimeUnit.SECONDS)
        .keepAliveWithoutCalls(true)
        .build()
    val asyncStub : ResponderServiceGrpc.ResponderServiceStub = 
        ResponderServiceGrpc.newStub(mChannel)
}

And the method is called from a foreground service.并且该方法是从前台服务调用的。

override fun onCreate() {
    super.onCreate()
    ...
    startForeground(MyNotificationBuilder.SERVICE_NOTIFICATION_ID, notificationBuilder.getServiceNotification())
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    val userId = sharedPreferencesManager.getInt(SharedPreferencesManager.USER_ID)
    val taskRequest = Responder.TaskRequest.newBuilder()
        .setUserId(userId)
        .build()

    grpcService.asyncStub.getTasks(taskRequest, object :
        StreamObserver<Responder.TaskResponse> {
        override fun onCompleted() {
            Log.d("grpc Tasks", "Completed")
        }

        override fun onError(t: Throwable?) {
            Log.d("grpc error cause", t?.cause.toString())
            t?.cause?.printStackTrace()
            Log.d("grpc error", "AFTER CAUSE")
            t!!.printStackTrace()
        }

        override fun onNext(value: Responder.TaskResponse?) {
            if (value != null) {
            
                when (value.command) {
                   ...
                }
            }
        }
    })
    return super.onStartCommand(intent, flags, startId)
}

The connection opens and stays open for about a minute of no communication and then fails with the following error.连接打开并保持打开状态大约一分钟没有通信,然后失败并出现以下错误。

D/grpc error cause: null
D/grpc error: AFTER CAUSE
io.grpc.StatusRuntimeException: INTERNAL: Internal error
io.grpc.Status.asRuntimeException(Status.java:533)
io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:460)
io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:426)
io.grpc.internal.ClientCallImpl.access$500(ClientCallImpl.java:66)
io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:689)
io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$900(ClientCallImpl.java:577)
io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:751)
io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:740)
io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)

The grpc-js server is created with the following options.使用以下选项创建 grpc-js 服务器。

var server = new grpc.Server({
    "grpc.http2.min_ping_interval_without_data_ms" : 10000,
    "grpc.keepalive_permit_without_calls" : true,
    "grpc.http2.min_time_between_pings_ms" : 10000,
    "grpc.keepalive_time_ms" : 10000,
    "grpc.http2.max_pings_without_data" : 0,
    'grpc.http2.min_ping_interval_without_data_ms':  5000
});

I never received the too many pings error either.我也从未收到too many pings错误。

I noticed that if there is periodic communication (like the server pinging the client with a small amount of data every 30s or so) through this connection then I don't get the error and the connection stays open for as long as the pinging continues (tested for 2 days).我注意到,如果通过此连接进行定期通信(例如服务器每 30 秒左右用少量数据 ping 客户端),那么我不会收到错误消息,并且只要 ping 继续,连接就会保持打开状态(测试 2 天)。

How do I keep the connection open without resorting to periodically pinging the client?如何在不诉诸定期 ping 客户端的情况下保持连接打开?

The managed channel has a property called keepAliveWithoutCalls which has a default value of false as seen here .托管通道有一个名为 keepAliveWithoutCalls 的属性,其默认值为 false ,如此处所示 If this is not set to true then the keepAlive will not happen if there are no current active calls happening.如果未将其设置为 true,则如果当前没有活动调用发生,则不会发生 keepAlive。 You would need to set this like so:您需要像这样设置:

private val mChannel = ManagedChannelBuilder
    .forAddress(GRPC_HOST_ADDRESS, GRPC_HOST_PORT)
    .usePlaintext()
    .keepAliveTime(30, TimeUnit.SECONDS)
    .keepAliveWithoutCalls(true)
    .build()

There is a possibility that you will have to do some other settings on the server as well to have the connection stay open without any data passing.您可能还必须在服务器上进行一些其他设置,以使连接保持打开状态而不传递任何数据。 You might get an error on the server saying "too many pings".您可能会在服务器上收到“ping 太多”的错误消息。 This happens because there are some other settings GRPC needs.发生这种情况是因为 GRPC 需要一些其他设置。 I am not sure exactly how to achieve this with a JS server but it shouldn't be too difficult.我不确定如何使用 JS 服务器来实现这一点,但这应该不会太难。 These settings include:这些设置包括:

GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS
Minimum allowed time between a server receiving successive ping frames without sending any data/header/window_update frame.

And this one:和这个:

GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS
Minimum time between sending successive ping frames without receiving any data/header/window_update frame, Int valued, milliseconds.

And this one:和这个:

GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS
Is it permissible to send keepalive pings without any outstanding streams.

There is a Keepalive User Guide for gRPC which I suggest you read through to understand how gRPC should keep connections open.有一个针对 gRPC 的 Keepalive 用户指南,我建议您通读以了解 gRPC 应该如何保持连接打开。 This is the core standard that all server and client implementations should follow, but I have noticed this is not always the case.这是所有服务器和客户端实现都应遵循的核心标准,但我注意到并非总是如此。 You can have a look at a previous but similar question I asked a while back here .你可以看看我之前问过的一个类似的问题

Have you tried the ManagedChannelBuilder.keepAliveTime setting ( https://github.com/grpc/grpc-java/blob/master/api/src/main/java/io/grpc/ManagedChannelBuilder.java#L357 )?您是否尝试过ManagedChannelBuilder.keepAliveTime设置( https://github.com/grpc/grpc-java/blob/master/api/src/main/java/io/grpc/ManagedChannelBuilder.java#L357 )? I am assuming it will work in the middle of a server streaming call.我假设它将在服务器流式调用中间工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM