-
Notifications
You must be signed in to change notification settings - Fork 49
scaleset: tolerate invalid instance status transitions in job message handlers #812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -122,10 +122,25 @@ func (w *Worker) HandleJobsCompleted(jobs []params.ScaleSetJobMessage) (err erro | |
| locking.Lock(job.RunnerName, w.consumerID) | ||
| _, err := w.store.UpdateInstance(w.ctx, job.RunnerName, runnerUpdateParams) | ||
| if err != nil { | ||
| if !errors.Is(err, runnerErrors.ErrNotFound) { | ||
| locking.Unlock(job.RunnerName, false) | ||
| return fmt.Errorf("updating runner %s: %w", job.RunnerName, err) | ||
| if errors.Is(err, runnerErrors.ErrNotFound) { | ||
| locking.Unlock(job.RunnerName, true) | ||
| continue | ||
| } | ||
| if errors.Is(err, runnerErrors.ErrBadRequest) { | ||
| // The instance is no longer in a state that can transition to | ||
| // pending_delete (e.g. it was already deleted or is being deleted | ||
| // by some other codepath, such as the reconciler noticing it went | ||
| // missing from the provider/github). There is nothing further for | ||
| // us to do here. Treating this as fatal would cause this message | ||
| // to be retried forever, since we never advance past it or delete | ||
| // it, blocking every subsequent message for this scale set. | ||
| slog.InfoContext(w.ctx, "runner already being handled/removed; ignoring completed job status update", | ||
| "runner_name", job.RunnerName, "error", err) | ||
| locking.Unlock(job.RunnerName, true) | ||
| continue | ||
| } | ||
| locking.Unlock(job.RunnerName, false) | ||
| return fmt.Errorf("updating runner %s: %w", job.RunnerName, err) | ||
| } | ||
| locking.Unlock(job.RunnerName, false) | ||
| } | ||
|
|
@@ -160,6 +175,16 @@ func (w *Worker) HandleJobsStarted(jobs []params.ScaleSetJobMessage) (err error) | |
| locking.Unlock(job.RunnerName, true) | ||
| continue | ||
| } | ||
| if errors.Is(err, runnerErrors.ErrBadRequest) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is interesting. The A reap operation usually tries to remove the runner from github first, then marks the runner as If a runner is forcefully removed from the provider while So I am unsure how this code path was triggered in your env. It may be a bug somewhere else, and I would like to track it down and fix the cause rather than treat the symptom. Could you share some debug logs by any chance that tracks a runner that has hit this? Are you using agent mode? Were any custom changes made to GARM that could impact this? |
||
| // The runner is already in a terminal/being-deleted state (e.g. it | ||
| // was reaped after going missing from the provider or github). Same | ||
| // reasoning as in HandleJobsCompleted: don't fail the whole message, | ||
| // or we'll retry it forever and block the scale set's message queue. | ||
| slog.InfoContext(w.ctx, "runner already being handled/removed; ignoring started job status update", | ||
| "runner_name", job.RunnerName, "error", err) | ||
| locking.Unlock(job.RunnerName, true) | ||
| continue | ||
| } | ||
| locking.Unlock(job.RunnerName, false) | ||
| return fmt.Errorf("updating runner %s: %w", job.RunnerName, err) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could indeed race if agent mode is used, but when in agent mode, the runner is set in
pending_deleteand eventually reaped. A retry here would hitErrNotFoundand should just continue. But we could find out more from logs if it you could share some (anonymized). You can find me on slack and we can debug this in private if it helps.