Executes the job, handling a panic if necessary (and various other error conditions). The named return value is so that we can still return a value in case of a panic. nolint:nonamedreturns
(ctx context.Context)
| 183 | // |
| 184 | //nolint:nonamedreturns |
| 185 | func (e *JobExecutor) execute(ctx context.Context) (res *jobExecutorResult) { |
| 186 | metadataUpdates := make(map[string]any) |
| 187 | ctx = context.WithValue(ctx, ContextKeyMetadataUpdates, metadataUpdates) |
| 188 | |
| 189 | defer func() { |
| 190 | if recovery := recover(); recovery != nil { |
| 191 | e.Logger.ErrorContext(ctx, e.Name+": panic recovery; possible bug with Worker", |
| 192 | slog.Int64("job_id", e.JobRow.ID), |
| 193 | slog.String("kind", e.JobRow.Kind), |
| 194 | slog.String("panic_val", fmt.Sprintf("%v", recovery)), |
| 195 | ) |
| 196 | |
| 197 | res = &jobExecutorResult{ |
| 198 | MetadataUpdates: metadataUpdates, |
| 199 | // Skip the first 4 frames which are: |
| 200 | // |
| 201 | // 1. The `runtime.Callers` function. |
| 202 | // 2. The `captureStackTraceSkipFrames` function. |
| 203 | // 3. The current recovery defer function. |
| 204 | // 4. The `JobExecutor.execute` method working the job. |
| 205 | PanicTrace: captureStackTraceSkipFrames(4), |
| 206 | PanicVal: recovery, |
| 207 | } |
| 208 | } |
| 209 | e.stats.RunDuration = e.Time.Now().Sub(e.start) |
| 210 | }() |
| 211 | |
| 212 | if e.WorkUnit == nil { |
| 213 | e.Logger.ErrorContext(ctx, e.Name+": Unhandled job kind", |
| 214 | slog.String("kind", e.JobRow.Kind), |
| 215 | slog.Int64("job_id", e.JobRow.ID), |
| 216 | ) |
| 217 | return &jobExecutorResult{Err: &rivertype.UnknownJobKindError{Kind: e.JobRow.Kind}, MetadataUpdates: metadataUpdates} |
| 218 | } |
| 219 | |
| 220 | doInner := execution.Func(func(ctx context.Context) error { |
| 221 | { |
| 222 | for _, hook := range append( |
| 223 | e.HookLookupGlobal.ByHookKind(hooklookup.HookKindWorkBegin), |
| 224 | e.WorkUnit.HookLookup(e.HookLookupByJob).ByHookKind(hooklookup.HookKindWorkBegin)..., |
| 225 | ) { |
| 226 | if err := hook.(rivertype.HookWorkBegin).WorkBegin(ctx, e.JobRow); err != nil { //nolint:forcetypeassert |
| 227 | return err |
| 228 | } |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | if err := e.WorkUnit.UnmarshalJob(); err != nil { |
| 233 | return err |
| 234 | } |
| 235 | |
| 236 | jobTimeout := cmp.Or(e.WorkUnit.Timeout(), e.ClientJobTimeout) |
| 237 | |
| 238 | if jobTimeout > 0 { |
| 239 | var timeoutCancel context.CancelFunc |
| 240 | ctx, timeoutCancel = context.WithTimeout(ctx, jobTimeout) |
| 241 | defer timeoutCancel() |
| 242 |
no test coverage detected