error.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /*
  2. Copyright 2023 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package wait
  14. import (
  15. "context"
  16. "errors"
  17. )
  18. // ErrWaitTimeout is returned when the condition was not satisfied in time.
  19. //
  20. // Deprecated: This type will be made private in favor of Interrupted()
  21. // for checking errors or ErrorInterrupted(err) for returning a wrapped error.
  22. var ErrWaitTimeout = ErrorInterrupted(errors.New("timed out waiting for the condition"))
  23. // Interrupted returns true if the error indicates a Poll, ExponentialBackoff, or
  24. // Until loop exited for any reason besides the condition returning true or an
  25. // error. A loop is considered interrupted if the calling context is cancelled,
  26. // the context reaches its deadline, or a backoff reaches its maximum allowed
  27. // steps.
  28. //
  29. // Callers should use this method instead of comparing the error value directly to
  30. // ErrWaitTimeout, as methods that cancel a context may not return that error.
  31. //
  32. // Instead of:
  33. //
  34. // err := wait.Poll(...)
  35. // if err == wait.ErrWaitTimeout {
  36. // log.Infof("Wait for operation exceeded")
  37. // } else ...
  38. //
  39. // Use:
  40. //
  41. // err := wait.Poll(...)
  42. // if wait.Interrupted(err) {
  43. // log.Infof("Wait for operation exceeded")
  44. // } else ...
  45. func Interrupted(err error) bool {
  46. switch {
  47. case errors.Is(err, errWaitTimeout),
  48. errors.Is(err, context.Canceled),
  49. errors.Is(err, context.DeadlineExceeded):
  50. return true
  51. default:
  52. return false
  53. }
  54. }
  55. // errInterrupted
  56. type errInterrupted struct {
  57. cause error
  58. }
  59. // ErrorInterrupted returns an error that indicates the wait was ended
  60. // early for a given reason. If no cause is provided a generic error
  61. // will be used but callers are encouraged to provide a real cause for
  62. // clarity in debugging.
  63. func ErrorInterrupted(cause error) error {
  64. switch cause.(type) {
  65. case errInterrupted:
  66. // no need to wrap twice since errInterrupted is only needed
  67. // once in a chain
  68. return cause
  69. default:
  70. return errInterrupted{cause}
  71. }
  72. }
  73. // errWaitTimeout is the private version of the previous ErrWaitTimeout
  74. // and is private to prevent direct comparison. Use ErrorInterrupted(err)
  75. // to get an error that will return true for Interrupted(err).
  76. var errWaitTimeout = errInterrupted{}
  77. func (e errInterrupted) Unwrap() error { return e.cause }
  78. func (e errInterrupted) Is(target error) bool { return target == errWaitTimeout }
  79. func (e errInterrupted) Error() string {
  80. if e.cause == nil {
  81. // returns the same error message as historical behavior
  82. return "timed out waiting for the condition"
  83. }
  84. return e.cause.Error()
  85. }