Closed
Description
Hello, I'd like to discuss and validate the best approach for detecting channel disconnection (offline) as quickly as possible.
Context:
- Our iOS/iPadOS app starts listening to a notification stream when it becomes active
- When the app goes to background, the channel with notification stream is closed
- iOS apps' active state typically lasts minutes, while iPadOS apps can remain active for hours or even days
- App needs to detect lost server connection within 5-10 seconds, even on poor networks (EDGE/3G) and needs to inform users about offline state promptly
So far it seems to me the best approach is using keepalive ping:
// With `GRPCChannelPool` config
configuration.keepalive = .init(
interval: .seconds(5),
timeout: .seconds(3),
permitWithoutCalls: true
)
// Or with `ClientConnection`
eventLoopGroup = PlatformSupport.makeEventLoopGroup(loopCount: 1)
var configuration = ClientConnection.Configuration.default(
target: target,
eventLoopGroup: eventLoopGroup
)
configuration.tlsConfiguration = .makeClientDefault(compatibleWith: eventLoopGroup)
configuration.connectionKeepalive = .init(
interval: .seconds(5),
timeout: .seconds(3),
permitWithoutCalls: true
)
channel = ClientConnection(configuration: configuration)
Current behavior:
- With this configuration, I get the error "unavailable (14): Transport became inactive" within 5 seconds when the device becomes disconnected (by turning Airplane mode on)
- However, with this configuration the client gets error "unavailable (14): Too many pings" during online active state after while. I guess this can likely be fixed by setting
GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA = 0
on the server side.
Questions:
- Is keepalive ping the best solution for my app? What else could be better?
- Are there any important considerations before using keepalive in production? The server will handle fewer than a few hundred clients, so keepalive pings shouldn't create significant load.
- When using this aggressive keepalive ping configuration, should other configuration also be adjusted?
- Which channel type is more suitable for my need?
ClientConnection
orPooledChannel
?ClientConnection
allows observingConnectivityState
viaConnectivityStateDelegate
- With
PooledChannel
, theConnectivityState
is not available to my knowledge, but I guess it's better to rely on thrown errors anyway - App will not handle many concurrent request
Thank you! I hope others who are new to gRPC (like me) will also find the answers useful.