MCPcopy Index your code
hub / github.com/coder/coder / process

Method process

coderd/notifications/notifier.go:158–204  ·  view source on GitHub ↗

process is responsible for coordinating the retrieval, processing, and delivery of messages. Messages are dispatched concurrently, but they may block when success/failure channels are full. NOTE: it is _possible_ that these goroutines could block for long enough to exceed CODER_NOTIFICATIONS_DISPAT

(ctx context.Context, success chan<- dispatchResult, failure chan<- dispatchResult)

Source from the content-addressed store, hash-verified

156// resulting in a failed attempt for each notification when their contexts are canceled; this is not possible with the
157// default configurations but could be brought about by an operator tuning things incorrectly.
158func (n *notifier) process(ctx context.Context, success chan<- dispatchResult, failure chan<- dispatchResult) error {
159 msgs, err := n.fetch(ctx)
160 if err != nil {
161 return xerrors.Errorf("fetch messages: %w", err)
162 }
163
164 n.log.Debug(ctx, "dequeued messages", slog.F("count", len(msgs)))
165
166 if len(msgs) == 0 {
167 return nil
168 }
169
170 var eg errgroup.Group
171 for _, msg := range msgs {
172 // If a notification template has been disabled by the user after a notification was enqueued, mark it as inhibited
173 if msg.Disabled {
174 failure <- n.newInhibitedDispatch(msg)
175 continue
176 }
177
178 // A message failing to be prepared correctly should not affect other messages.
179 deliverFn, err := n.prepare(ctx, msg)
180 if err != nil {
181 if database.IsQueryCanceledError(err) {
182 n.log.Debug(ctx, "dispatcher construction canceled", slog.F("msg_id", msg.ID), slog.Error(err))
183 } else {
184 n.log.Error(ctx, "dispatcher construction failed", slog.F("msg_id", msg.ID), slog.Error(err))
185 }
186 failure <- n.newFailedDispatch(msg, err, xerrors.Is(err, decorateHelpersError{}))
187 n.metrics.PendingUpdates.Set(float64(len(success) + len(failure)))
188 continue
189 }
190
191 eg.Go(func() error {
192 // Dispatch must only return an error for exceptional cases, NOT for failed messages.
193 return n.deliver(ctx, msg, deliverFn, success, failure)
194 })
195 }
196
197 if err = eg.Wait(); err != nil {
198 n.log.Debug(ctx, "dispatch failed", slog.Error(err))
199 return xerrors.Errorf("dispatch failed: %w", err)
200 }
201
202 n.log.Debug(ctx, "batch completed", slog.F("count", len(msgs)))
203 return nil
204}
205
206// fetch retrieves messages from the queue by "acquiring a lease" whereby this notifier is the exclusive handler of these
207// messages until they are dispatched - or until the lease expires (in exceptional cases).

Callers 1

runMethod · 0.95

Calls 12

fetchMethod · 0.95
newInhibitedDispatchMethod · 0.95
prepareMethod · 0.95
newFailedDispatchMethod · 0.95
deliverMethod · 0.95
IsQueryCanceledErrorFunction · 0.92
GoMethod · 0.80
SetMethod · 0.65
WaitMethod · 0.65
ErrorfMethod · 0.45
ErrorMethod · 0.45
IsMethod · 0.45

Tested by

no test coverage detected