Skip to content

fix(runners,tasks): critical runner requeue and finalization bugs#4004

Closed
cursor[bot] wants to merge 2 commits into
developfrom
cursor/critical-bug-investigation-bc50
Closed

fix(runners,tasks): critical runner requeue and finalization bugs#4004
cursor[bot] wants to merge 2 commits into
developfrom
cursor/critical-bug-investigation-bc50

Conversation

@cursor

@cursor cursor Bot commented Jul 3, 2026

Copy link
Copy Markdown

Summary

Daily critical-bug inspection found three high-severity correctness bugs still present on develop. This PR applies minimal, previously validated fixes.

Bugs and impact

1. Duplicate dispatch on ErrAllRunnersBusy requeue

Impact: When all runners are at capacity, a task can be dispatched twice (duplicate Ansible/Terraform execution).

Trigger: TaskRunner.run enqueued the task while it still sat in the running set, then sent EventTypeRequeued from a defer. A concurrent queue tick could ClaimAndDequeue the task in that window.

Fix: Release running/active bookkeeping via onTaskStop before enqueueing; notify the pool synchronously (matching reconciler requeue paths).

2. Stopped → failed on runner after terminated_jobs

Impact: Server emergency-stop (terminated_jobs) is reported to users as failed instead of stopped.

Trigger: applyTerminatedJobs sets status to stopped and kills the job; when Run() unwinds with an error, the error path overwrote the terminal status.

Fix: Add finalizeAfterRun that respects an already-finished status.

3. HA pool state leak in failTaskRunnerLost

Impact: Leaked running/active Redis state; skipped finish webhook and autorun children.

Trigger: Reconciler won the finalize lock but observed the DB already terminal, then returned early without finalizeRemoteTaskLocked.

Fix: Complete finalization when DB is already terminal; harden offline requeue with DB re-check and rollback on persist failure.

Validation

  • go test ./services/tasks/... ./services/runners/... — all pass (includes new regression tests)

Scope inspected (no new critical issues)

  • New commits since last run: OIDC dep bump, Renovate config, Dockerfile paramiko — no behavioral risk found
  • JWT runner auth, encryption key removal, integrations DI — no new critical issues
Open in Web View Automation 

cursoragent and others added 2 commits July 3, 2026 11:03
When every runner is at capacity, ErrAllRunnersBusy requeued tasks by
enqueueing them while they still sat in the running set, then sending
EventTypeRequeued from a defer. A periodic queue tick could
ClaimAndDequeue the task in that window and start a second dispatch on
the same TaskRunner.

Release running/active bookkeeping before enqueueing and notify the pool
synchronously, matching the reconciler requeue paths.

Co-authored-by: Denis Gukov <fiftin@outlook.com>
…finalization

Runner client: when applyTerminatedJobs emergency-stops a job and Run()
unwinds with an error, the error path overwrote stopped with failed.
Add finalizeAfterRun that respects an already-finished status.

HA reconciler: when failTaskRunnerLost wins the finalize lock but the DB
already has a terminal status, complete finalization instead of bailing
so pool/Redis state and autorun children are not leaked. Harden offline
requeue with a pre-mutation DB re-check and rollback on persist failure.

Co-authored-by: Denis Gukov <fiftin@outlook.com>
@fiftin fiftin closed this Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants