github.com/lingyao2333/mo-zero@v1.4.1/zrpc/internal/serverinterceptors/timeoutinterceptor.go (about)

     1  package serverinterceptors
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"runtime/debug"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"google.golang.org/grpc"
    12  	"google.golang.org/grpc/codes"
    13  	"google.golang.org/grpc/status"
    14  )
    15  
    16  // UnaryTimeoutInterceptor returns a func that sets timeout to incoming unary requests.
    17  func UnaryTimeoutInterceptor(timeout time.Duration) grpc.UnaryServerInterceptor {
    18  	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
    19  		handler grpc.UnaryHandler) (interface{}, error) {
    20  		ctx, cancel := context.WithTimeout(ctx, timeout)
    21  		defer cancel()
    22  
    23  		var resp interface{}
    24  		var err error
    25  		var lock sync.Mutex
    26  		done := make(chan struct{})
    27  		// create channel with buffer size 1 to avoid goroutine leak
    28  		panicChan := make(chan interface{}, 1)
    29  		go func() {
    30  			defer func() {
    31  				if p := recover(); p != nil {
    32  					// attach call stack to avoid missing in different goroutine
    33  					panicChan <- fmt.Sprintf("%+v\n\n%s", p, strings.TrimSpace(string(debug.Stack())))
    34  				}
    35  			}()
    36  
    37  			lock.Lock()
    38  			defer lock.Unlock()
    39  			resp, err = handler(ctx, req)
    40  			close(done)
    41  		}()
    42  
    43  		select {
    44  		case p := <-panicChan:
    45  			panic(p)
    46  		case <-done:
    47  			lock.Lock()
    48  			defer lock.Unlock()
    49  			return resp, err
    50  		case <-ctx.Done():
    51  			err := ctx.Err()
    52  			if err == context.Canceled {
    53  				err = status.Error(codes.Canceled, err.Error())
    54  			} else if err == context.DeadlineExceeded {
    55  				err = status.Error(codes.DeadlineExceeded, err.Error())
    56  			}
    57  			return nil, err
    58  		}
    59  	}
    60  }