Wait waits until the most recent attempt finishes (i.e., "done" is closed) or until the context is canceled. If the task has never begun (still pending), Wait will block until it eventually starts or ctx is canceled.
(ctx context.Context)
| 98 | // or until the context is canceled. |
| 99 | // If the task has never begun (still pending), Wait will block until it eventually starts or ctx is canceled. |
| 100 | func (t *BootstrapTask) Wait(ctx context.Context) error { |
| 101 | for { |
| 102 | state := TaskState(t.state.Load()) |
| 103 | if state == TaskSucceeded || state == TaskFailed || state == TaskTimedOut || state == TaskFatal { |
| 104 | lastErr, ok := t.lastErr.Load().(wrappedError) |
| 105 | if ok && lastErr.err != nil { |
| 106 | return lastErr.err |
| 107 | } |
| 108 | return nil |
| 109 | } |
| 110 | ch := t.doneVal.Load() |
| 111 | if ch == nil { |
| 112 | // The task hasn't started an attempt yet. If the state is no longer pending, break out. |
| 113 | if state != TaskPending { |
| 114 | // It's either running, failed, or succeeded => loop again so we re-fetch the channel. |
| 115 | continue |
| 116 | } |
| 117 | // We'll just do a short sleep or yield. |
| 118 | select { |
| 119 | case <-ctx.Done(): |
| 120 | return ctx.Err() |
| 121 | case <-time.After(10 * time.Millisecond): |
| 122 | // keep looping until the task actually starts |
| 123 | continue |
| 124 | } |
| 125 | } else { |
| 126 | // We have a valid channel. Wait on it or until context is canceled. |
| 127 | select { |
| 128 | case <-ctx.Done(): |
| 129 | return ctx.Err() |
| 130 | case <-ch.(chan struct{}): |
| 131 | // The attempt ended. Check if we failed. |
| 132 | if TaskState(t.state.Load()) == TaskFailed { |
| 133 | wr, _ := t.lastErr.Load().(wrappedError) |
| 134 | if wr.err == nil { |
| 135 | t.lastErr.Store(wrappedError{err: errors.New("task failed without specific error")}) |
| 136 | } |
| 137 | return wr.err |
| 138 | } |
| 139 | return nil // Succeeded or otherwise finished |
| 140 | } |
| 141 | } |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | // attempt is called just before a new attempt to run t.Fn. |
| 146 | func (t *BootstrapTask) beginAttempt() { |