deadline.go 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. // Package deadline implements the deadline (also known as "timeout") resiliency pattern for Go.
  2. package deadline
  3. import (
  4. "errors"
  5. "time"
  6. )
  7. // ErrTimedOut is the error returned from Run when the deadline expires.
  8. var ErrTimedOut = errors.New("timed out waiting for function to finish")
  9. // Deadline implements the deadline/timeout resiliency pattern.
  10. type Deadline struct {
  11. timeout time.Duration
  12. }
  13. // New constructs a new Deadline with the given timeout.
  14. func New(timeout time.Duration) *Deadline {
  15. return &Deadline{
  16. timeout: timeout,
  17. }
  18. }
  19. // Run runs the given function, passing it a stopper channel. If the deadline passes before
  20. // the function finishes executing, Run returns ErrTimeOut to the caller and closes the stopper
  21. // channel so that the work function can attempt to exit gracefully. It does not (and cannot)
  22. // simply kill the running function, so if it doesn't respect the stopper channel then it may
  23. // keep running after the deadline passes. If the function finishes before the deadline, then
  24. // the return value of the function is returned from Run.
  25. func (d *Deadline) Run(work func(<-chan struct{}) error) error {
  26. result := make(chan error)
  27. stopper := make(chan struct{})
  28. go func() {
  29. result <- work(stopper)
  30. }()
  31. select {
  32. case ret := <-result:
  33. return ret
  34. case <-time.After(d.timeout):
  35. close(stopper)
  36. return ErrTimedOut
  37. }
  38. }