timeout.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. package fx
  2. import (
  3. "context"
  4. "time"
  5. )
  6. var (
  7. // ErrCanceled is the error returned when the context is canceled.
  8. ErrCanceled = context.Canceled
  9. // ErrTimeout is the error returned when the context's deadline passes.
  10. ErrTimeout = context.DeadlineExceeded
  11. )
  12. // DoOption defines the method to customize a DoWithTimeout call.
  13. type DoOption func() context.Context
  14. // DoWithTimeout runs fn with timeout control.
  15. func DoWithTimeout(fn func() error, timeout time.Duration, opts ...DoOption) error {
  16. parentCtx := context.Background()
  17. for _, opt := range opts {
  18. parentCtx = opt()
  19. }
  20. ctx, cancel := context.WithTimeout(parentCtx, timeout)
  21. defer cancel()
  22. // create channel with buffer size 1 to avoid goroutine leak
  23. done := make(chan error, 1)
  24. panicChan := make(chan interface{}, 1)
  25. go func() {
  26. defer func() {
  27. if p := recover(); p != nil {
  28. panicChan <- p
  29. }
  30. }()
  31. done <- fn()
  32. }()
  33. select {
  34. case p := <-panicChan:
  35. panic(p)
  36. case err := <-done:
  37. return err
  38. case <-ctx.Done():
  39. return ctx.Err()
  40. }
  41. }
  42. // WithContext customizes a DoWithTimeout call with given ctx.
  43. func WithContext(ctx context.Context) DoOption {
  44. return func() context.Context {
  45. return ctx
  46. }
  47. }