-
Notifications
You must be signed in to change notification settings - Fork 427
Best way to get bytes sent / bytes downloaded from gRPC #2216
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
Comments
Do you want to trace the bytes sent/received across a whole connection or per RPC? And are you using v1 or v2? |
Whole connection is OK given that it would be difficult to split and on client, we only have 1 or 2 RPC call at the same time (likely 1). Currently on v1 but can upgrade to v2 if calls for it. |
Okay great, we can work with that. I think the best option here is to create a NIO Here's a rough sketch of how it could look: final class ByteRecordingHandler: ChannelDuplexHandler {
typealias InboundIn = ByteBuffer
typealias InboundOut = ByteBuffer
typealias OutboundIn = ByteBuffer
typealias OutboundOut = ByteBuffer
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
// Unwrap the NIOAny to get a ByteBuffer
let buffer = Self.unwrapInboundIn(data)
let byteCount = buffer.readableBytes
// ... record bytes received
// Forward the bytes we read
context.fireChannelRead(data)
}
func write(context: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
// Unwrap the NIOAny to get a ByteBuffer
let buffer = Self.unwrapOutboundIn(data)
let byteCount = buffer.readableBytes
// ... record bytes sent
// Forward the bytes
context.write(data, promise: promise)
}
} Then you'll need to plug this into your client: let channel = try GRPCChannelPool.with(
target: .host("localhost", port: 1234),
transportSecurity: .plaintext,
eventLoopGroup: group
) {
$0.debugChannelInitializer = { channel in
channel.eventLoop.makeCompletedFuture {
let sync = channel.pipeline.syncOperations
let http2Handler = try sync.handler(type: NIOHTTP2Handler.self)
// Note: this closure is called for every new connection, so you should
// emit any events to a shared `Sendable` object held by the `ByteRecordingHandler`.
// That object will be the bridge between the connection and your application.
let recorder = ByteRecordingHandler(...)
try sync.addHandler(recorder, position: .before(http2Handler))
}
}
} Hopefully this'll set you off on the right path, let me know if you need more help! |
Is your feature request related to a problem? Please describe it.
My use case for gPRC is on client - server connection. As such, there are cases client is on unstable connection and customers would benefit from getting better understanding of how long they need to wait for a certain call to complete. As such, we would like to provide feedback on the progress bar for how many bytes sent / how many bytes downloaded on per-frame level. This currently is not possible.
Describe the solution you'd like
There are several ways to implement this. It seems require a bit more thinking. On macOS / iOS platform in particular, it seem implementing custom NWFramerImplementation and insert it into NWParameters would be the most straightforward, but that requires change to SwiftNIOTransportService, a library upstream to grpc-swift.
I also explored some other ways, but it all pointing to changes required in SwiftNIO upstream library.
Describe alternatives you've considered
Alternatively, we can use interceptor, but that is inaccurate and won't reflect how much bytes sent / how much bytes downloaded while a call is still in progress.
Another alternative is to initialize bidirectional streaming call, and support chunking there. But that requires some complications on our gRPC schema itself.
The text was updated successfully, but these errors were encountered: