StartInit should be invoked at the beginning of a service's Start function. It returns a context for the service to use, a boolean indicating whether it should start (which will be false if the service is already started), and a stopped channel. Services should defer a close on the stop channel in t
(ctx context.Context)
| 105 | // |
| 106 | // ... |
| 107 | func (s *BaseStartStop) StartInit(ctx context.Context) (context.Context, bool, func(), func()) { |
| 108 | s.mu.Lock() |
| 109 | defer s.mu.Unlock() |
| 110 | |
| 111 | if s.isRunning { |
| 112 | // If stopped has already been closed (e.g. a previous Start failed and |
| 113 | // called stopped()), reset state so the service can start again. |
| 114 | // |
| 115 | // Notably, for this branch to be taken, Stop will not have been called. |
| 116 | // If it was, isRunning will have been set to false via finalizeStop. |
| 117 | if s.stopped != nil { |
| 118 | select { |
| 119 | case <-s.stopped: |
| 120 | s.isRunning = false |
| 121 | s.started = nil |
| 122 | s.stopped = nil |
| 123 | default: |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | if s.isRunning { |
| 128 | return ctx, false, nil, nil |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | s.isRunning = true |
| 133 | |
| 134 | // Only allocate a started or stopped channels when not preallocated by |
| 135 | // Started or Stopped. |
| 136 | if s.started == nil { |
| 137 | s.started = make(chan struct{}) |
| 138 | } |
| 139 | if s.stopped == nil { |
| 140 | s.stopped = make(chan struct{}) |
| 141 | } |
| 142 | |
| 143 | ctx, s.cancelFunc = context.WithCancelCause(ctx) |
| 144 | |
| 145 | closeStartedOnce := sync.OnceFunc(func() { close(s.started) }) |
| 146 | |
| 147 | return ctx, true, closeStartedOnce, func() { |
| 148 | // Also close the started channel (in case it wasn't already), just in |
| 149 | // case `started()` was never invoked and someone is waiting on it. |
| 150 | closeStartedOnce() |
| 151 | |
| 152 | close(s.stopped) |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | // Started returns a channel that's closed when a service finishes starting, or |
| 157 | // if failed to start and is stopped instead. It can be used in conjunction with |