weima
weima

Reputation: 4912

grpc go : how to know in server side, when client closes the connection

I am using grpc go

i have an rpc which looks roughly like this

196 service MyService {
197   // Operation 1
198   rpc Operation1(OperationRequest) returns (OperationResponse) {
199       option (google.api.http) = {
200         post: "/apiver/myser/oper1"
201         body: "*"
202     };
203   }

Client connects by using grpc.Dial() method

When a client connects, the server does some book keeping. when the client disconnects, the bookkeeping needs to be removed.

is there any callback that can be registered which can be used to know that client has closed the session.

Upvotes: 14

Views: 19053

Answers (3)

Franci
Franci

Reputation: 2245

Based on your code, it's an unary rpc call, the client connect to server for only one time, send a request and get a response. The client will wait for the response until timeout.

In server side streaming, you can get the client disconnect from

<-grpc.ServerStream.Context.Done()

signal.

With that above, you can implement your own channel in a go routine to build your logic. Use select statement as:

select {
    case <-srv.Context().Done():
        return
    case res := <-<YOUR OWN CHANNEL, WITH RECEIVED RESQUEST OR YOUR RESPONSE>
        ....
}

I provide some detailed code here

In client streaming, besides the above signal, you can check whether the server can receive the msg:

req, err := grpc.ServerStream.Recv()
if err == io.EOF {
    break
} else if err != nil {
    return err
}

Upvotes: 9

虫子樱桃
虫子樱桃

Reputation: 51

as the github issue:link you can do like this

err = stream.Context().Err()
if err != nil {
    break
}

Upvotes: 0

Zak
Zak

Reputation: 5898

Assuming that the server is implemented in go, there's an API on the *grpc.ClientConn that reports state changes in the connection.

func (cc *ClientConn) WaitForStateChange(ctx context.Context, sourceState connectivity.State) bool

https://godoc.org/google.golang.org/grpc#ClientConn.WaitForStateChange

These are the docs on each of the connectivity.State

https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md

If you need to expose a channel that you can listen to for the client closing the connection then you could do something like this:

func connectionOnState(ctx context.Context, conn *grpc.ClientConn, states ...connectivity.State) <-chan struct{} {
    done := make(chan struct{})

    go func() {
        // any return from this func will close the channel
        defer close(done)

        // continue checking for state change 
        // until one of break states is found
        for { 
            change := conn.WaitForStateChange(ctx, conn.GetState())
            if !change {
                // ctx is done, return
                // something upstream is cancelling
                return
            }

            currentState := conn.GetState()

            for _, s := range states {
                if currentState == s {
                    // matches one of the states passed
                    // return, closing the done channel
                    return 
                }
            }
        }
    }()

    return done
}

If you only want to consider connections that are shutting down or shutdown, then you could call it like so:

// any receives from shutdownCh will mean the state Shutdown
shutdownCh := connectionOnState(ctx, conn, connectivity.Shutdown) 

Upvotes: 1

Related Questions