| 145 | } |
| 146 | |
| 147 | func (e *JobExecutor) Execute(ctx context.Context) { |
| 148 | // Ensure that the context is cancelled no matter what, or it will leak: |
| 149 | defer e.CancelFunc(errExecutorDefaultCancel) |
| 150 | |
| 151 | e.start = e.Time.Now() |
| 152 | e.stats = &jobstats.JobStatistics{ |
| 153 | QueueWaitDuration: e.start.Sub(e.JobRow.ScheduledAt), |
| 154 | } |
| 155 | |
| 156 | res := e.execute(ctx) |
| 157 | if res.Err != nil && errors.Is(context.Cause(ctx), rivertype.ErrJobCancelledRemotely) { |
| 158 | res.Err = context.Cause(ctx) |
| 159 | } |
| 160 | |
| 161 | var multiJobErrors withJobsAndErrorsByID |
| 162 | if res.Err != nil { |
| 163 | multiJobErrors, _ = res.Err.(withJobsAndErrorsByID) |
| 164 | } |
| 165 | |
| 166 | if multiJobErrors == nil { |
| 167 | e.reportResult(ctx, e.JobRow, res) |
| 168 | } else { |
| 169 | errorsByID := multiJobErrors.ErrorsByID() |
| 170 | for _, jobRow := range multiJobErrors.Jobs() { |
| 171 | jobSpecificRes := *res |
| 172 | jobSpecificRes.Err = errorsByID[jobRow.ID] |
| 173 | e.reportResult(ctx, jobRow, &jobSpecificRes) |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | e.ProducerCallbacks.JobDone(e.JobRow) |
| 178 | } |
| 179 | |
| 180 | // Executes the job, handling a panic if necessary (and various other error |
| 181 | // conditions). The named return value is so that we can still return a value in |