Skip to content
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

otelgrpc: goroutine leak if Recv is not called #502

Closed
glazychev-art opened this issue Dec 25, 2020 · 8 comments
Closed

otelgrpc: goroutine leak if Recv is not called #502

glazychev-art opened this issue Dec 25, 2020 · 8 comments
Assignees
Labels
area: instrumentation Related to an instrumentation package bug Something isn't working
Milestone

Comments

@glazychev-art
Copy link
Contributor

glazychev-art commented Dec 25, 2020

Hello,
This problem is related to StreamClientInterceptor.
The goroutine is creating inside wrapClientStream and it is waiting for events (ex. from RecvMsg)
https://github.com/open-telemetry/opentelemetry-go-contrib/blob/master/instrumentation/google.golang.org/grpc/otelgrpc/interceptor.go#L279-L280

What if we create clientStream and never call stream.Recv()? Seems there will be a goleak, because goroutine is waiting for events to quit.

Thank you

@glazychev-art glazychev-art changed the title otelgrpc: otelgrpc: goroutine leak if Recv is not called Dec 25, 2020
@MrAlias MrAlias added the bug Something isn't working label Jan 7, 2021
@MrAlias MrAlias added the area: instrumentation Related to an instrumentation package label Jan 7, 2021
@XSAM XSAM self-assigned this Feb 16, 2021
@XSAM
Copy link
Member

XSAM commented Feb 16, 2021

clientStream considers grpc.ClientStream.CloseSend() as a kind of events. So after grpc.ClientStream.CloseSend() is called, the goroutine that is waiting for events will correctly exit.

func (w *clientStream) CloseSend() error {
err := w.ClientStream.CloseSend()
if err != nil {
w.sendStreamEvent(errorEvent, err)
} else {
w.sendStreamEvent(closeEvent, nil)
}
return err
}

It seems no goroutine will leak because of no stream.Recv() be called.

@glazychev-art
Copy link
Contributor Author

Yes, but if we look at this:

for event := range events {
switch event.Type {
case closeEvent:
state |= clientClosedState
case receiveEndEvent:
state |= receiveEndedState
case errorEvent:
finished <- event.Err
return
}
if state == clientClosedState|receiveEndedState {
finished <- nil
return
}
}

we can see that return will happen if we get errorEvent OR (closeEvent AND receiveEndEvent).
You are right, we can get CloseEvent from CloseSend(), but ReceiveEndEvent will never happen if we don't call RecvMsg.
Maybe the condition should be like this:

			if (state & clientClosedState) != 0 || (state & receiveEndedState) != 0  {
				finished <- nil
				return
			}

Correct me if I am wrong

@XSAM
Copy link
Member

XSAM commented Feb 17, 2021

@glazychev-art You're right that goroutine will leak if we don't call RecvMsg. But it is not a complete gRPC call if we don't call RecvMsg.

Also, CloseSend only means closing the send direction of the stream, not the entire stream, which means the stream is still on, and we can't end the span at this time.

@denis-tingaikin
Copy link

denis-tingaikin commented Feb 18, 2021

@XSAM Is it possible to wait for <-stream.Context().Done() and close all resources when it happens? I guess it could solve the problem with

if we don't call RecvMsg. But it is not a complete gRPC call if we don't call RecvMsg.

@XSAM
Copy link
Member

XSAM commented Feb 19, 2021

Is it possible to wait for <-stream.Context().Done() and close all resources when it happens?

@denis-tingaikin It might not be a solution here since the context can't be called before RecvMsg

Context() should not be called until after Header or RecvMsg has returned.

https://github.com/grpc/grpc-go/blob/577eb696279ea85069a02c9a4c2defafdab858c5/stream.go#L93-L97

@XSAM XSAM closed this as completed Feb 24, 2021
@denis-tingaikin
Copy link

This issue still actual.

Moreover, it is not reproducible if we are using jaeger directly.

@XSAM
Copy link
Member

XSAM commented Feb 25, 2021

@denis-tingaikin I can't reproduce this bug.

What version of the otelgrpc you are using? Also, what's the scenario that users might not call RecvMsg.

@XSAM XSAM reopened this Feb 25, 2021
plantfansam referenced this issue in plantfansam/opentelemetry-go-contrib Mar 18, 2022
The `go.opentelemetry.io/otel/exporter/trace/jaeger` package was
mistakenly released with a `v1.0.0` tag instead of `v0.1.0`. This
resulted in all subsequent releases not becoming the default latest,
meaning that `go get`s pulled in the incompatible `v0.1.0` release of
that package when pulling in more recent packages from other otel
packages. Renaming the `exporter` directory to `exporters` fixes this
issue by consequentially renaming the package.

Additionally, this action also renames *all* exporters. This is
understood to be a disruptive action to existing users as they will need
to update any dependencies they currently have on our exporters.
However, it was decided to take this action regardless. The need to
resolve the existing issue explained above is highly important, and
given the Alpha state of this project these kinds of breaking changes
should be expected (though not without reason).

Resolves #331

Co-authored-by: Rahul Patel <rghetia@yahoo.com>
@glazychev-art
Copy link
Contributor Author

It seems it has been fixed - #840
Feel free to reopen

@pellared pellared added this to the untracked milestone Nov 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: instrumentation Related to an instrumentation package bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants