Distribute a single event into any listening subscriber channels. Job events should specify the job and stats, while queue events should only specify the queue. MUST be called with sm.mu already held.
(ctx context.Context, job *rivertype.JobRow, stats *JobStatistics, snoozed bool)
| 153 | // |
| 154 | // MUST be called with sm.mu already held. |
| 155 | func (sm *subscriptionManager) distributeJobEvent(ctx context.Context, job *rivertype.JobRow, stats *JobStatistics, snoozed bool) { |
| 156 | var event *Event |
| 157 | if snoozed { |
| 158 | event = &Event{Kind: EventKindJobSnoozed, Job: job, JobStats: stats} |
| 159 | } else { |
| 160 | switch job.State { |
| 161 | case rivertype.JobStateCancelled: |
| 162 | event = &Event{Kind: EventKindJobCancelled, Job: job, JobStats: stats} |
| 163 | case rivertype.JobStateCompleted: |
| 164 | event = &Event{Kind: EventKindJobCompleted, Job: job, JobStats: stats} |
| 165 | case rivertype.JobStateAvailable, rivertype.JobStateDiscarded, rivertype.JobStateRetryable, rivertype.JobStateRunning: |
| 166 | event = &Event{Kind: EventKindJobFailed, Job: job, JobStats: stats} |
| 167 | case rivertype.JobStatePending, rivertype.JobStateScheduled: |
| 168 | // job state may be set to scheduled, but only for snoozed jobs, so |
| 169 | // the case at the top should always take precedence before this |
| 170 | panic(fmt.Sprintf("completion subscriber unexpectedly received job in %s state, river bug", job.State)) |
| 171 | default: |
| 172 | // linter exhaustive rule prevents this from being reached |
| 173 | panic("unreachable state to distribute, river bug") |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | // All subscription channels are non-blocking so this is always fast and |
| 178 | // there's no risk of falling behind what producers are sending. |
| 179 | for _, sub := range sm.subscriptions { |
| 180 | if sub.ListensFor(event.Kind) { |
| 181 | // TODO: THIS IS UNSAFE AND WILL LEAD TO DROPPED EVENTS. |
| 182 | // |
| 183 | // We are allocating subscriber channels with a fixed size of 1000, but |
| 184 | // potentially processing job events in batches of 5000 (batch completer |
| 185 | // max batch size). It's probably not possible for the subscriber to keep |
| 186 | // up with these bursts. |
| 187 | select { |
| 188 | case sub.Chan <- event: |
| 189 | default: |
| 190 | sm.Logger.WarnContext(ctx, sm.Name+": Subscription event dropped due to full buffer", |
| 191 | slog.String("event_kind", string(event.Kind)), |
| 192 | ) |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | func (sm *subscriptionManager) distributeQueueEvent(event *Event) { |
| 199 | sm.distributeQueueEventWithContext(context.Background(), event) |
no test coverage detected