timeoutinterceptor.go 1.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. package serverinterceptors
  2. import (
  3. "context"
  4. "sync"
  5. "time"
  6. "github.com/tal-tech/go-zero/core/contextx"
  7. "google.golang.org/grpc"
  8. )
  9. // UnaryTimeoutInterceptor returns a func that sets timeout to incoming unary requests.
  10. func UnaryTimeoutInterceptor(timeout time.Duration) grpc.UnaryServerInterceptor {
  11. return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
  12. handler grpc.UnaryHandler) (interface{}, error) {
  13. ctx, cancel := contextx.ShrinkDeadline(ctx, timeout)
  14. defer cancel()
  15. var resp interface{}
  16. var err error
  17. var lock sync.Mutex
  18. done := make(chan struct{})
  19. // create channel with buffer size 1 to avoid goroutine leak
  20. panicChan := make(chan interface{}, 1)
  21. go func() {
  22. defer func() {
  23. if p := recover(); p != nil {
  24. panicChan <- p
  25. }
  26. }()
  27. lock.Lock()
  28. defer lock.Unlock()
  29. resp, err = handler(ctx, req)
  30. close(done)
  31. }()
  32. select {
  33. case p := <-panicChan:
  34. panic(p)
  35. case <-done:
  36. lock.Lock()
  37. defer lock.Unlock()
  38. return resp, err
  39. case <-ctx.Done():
  40. return nil, ctx.Err()
  41. }
  42. }
  43. }