frostfs-sdk-go/api/rpc/client/stream_wrapper.go
Dmitrii Stepanov 593dd77d84
[#327] rpc: Fix mem leak
gRPC stream must be closed by `cancel` to prevent memleak.

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2025-01-30 12:53:43 +03:00

67 lines
1.2 KiB
Go

package client
import (
"context"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message"
"google.golang.org/grpc"
)
type streamWrapper struct {
grpc.ClientStream
timeout time.Duration
cancel context.CancelFunc
}
func (w streamWrapper) ReadMessage(m message.Message) error {
// Can be optimized: we can create blank message here.
gm := m.ToGRPCMessage()
err := w.withTimeout(func() error {
return w.ClientStream.RecvMsg(gm)
})
if err != nil {
return err
}
return m.FromGRPCMessage(gm)
}
func (w streamWrapper) WriteMessage(m message.Message) error {
return w.withTimeout(func() error {
return w.ClientStream.SendMsg(m.ToGRPCMessage())
})
}
func (w *streamWrapper) closeSend() error {
return w.withTimeout(w.ClientStream.CloseSend)
}
func (w *streamWrapper) Close() error {
w.cancel()
return nil
}
func (w *streamWrapper) withTimeout(closure func() error) error {
ch := make(chan error, 1)
go func() {
ch <- closure()
close(ch)
}()
tt := time.NewTimer(w.timeout)
select {
case err := <-ch:
tt.Stop()
select {
case <-tt.C:
default:
}
return err
case <-tt.C:
w.cancel()
return context.DeadlineExceeded
}
}