myxce/.wolf/bugs/bug-1899.md
Rongsong Shen db16b565dd
chore(buglog): bug-1899 fixed (40207402)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 12:29:28 +00:00

4.1 KiB

id status status_updated status_note component severity timestamp last_seen occurrences files tags related fix_commits
bug-1899 fixed 2026-10-01 apiserver wrong-result 2026-10-01T05:10:35Z 2026-10-01T05:10:35Z 1
src/frontend/apiserver/controllers/jobs.go
apiserver
control
job-array
code-review
bug-1898
bug-1896
40207402

bug-1899: ControlJobByID re-dispatches earlier selections on every later selection of one request

Description

Observed: found by code review, no failing run captured yet. In ControlJobByID the slice successJobs is declared once before the loop over the request's selections (src/frontend/apiserver/controllers/jobs.go:2464), is appended to inside that loop (:2575-2583), and the dispatch loop over the whole accumulated slice also sits inside it (:2594-2617):

successJobs := []map[string]interface{}{}            // :2464, outside
for _, ujobFilterCdArray := range allFiltCdArrays {   // one per selection
    ...
    successJobs = append(successJobs, ...)           // :2575
    if len(successJobs) > 0 {
        for _, successJob := range successJobs {      // re-sends all earlier ones
            err = backend.ControlJob(...)              // :2611

Expected: each selected job receives the control action once per request; the response lists it once. Impact: wrong result: xcecli jobs kill X[1],Y[2] (or kill A,B) signals the first selection's jobs once per later selection (N selections -> the first job is sent N times); a repeated kill of an already-killed job can make the backend call fail and the request report an error; BuildBatchOperationResponse receives the accumulated slice, so the response lists earlier jobs repeatedly. Distinct from the out-of-scope duplicate-signal case of one element selected twice (job-array-one-based-index requirements). Found by: review (design review round 11 of spec job-array-one-based-index, 2026-10-01)

Environment

  • OS: no /etc/os-release; Docker container; NixOS kernel; kernel Linux 6.18.33 x86_64
  • libc: n/a (pure-Go control handler); host glibc 2.40
  • Toolchain: gcc (GCC) 15.2.0, meson 1.9.1
  • Build: asan (xce.build); defect is in pure Go, independent of profile
  • Code: scheduler-framework @ 8f5ba635-dirty
  • Deployment: any (single-node or HA) with at least two controllable jobs

Reproduction

  1. Read src/frontend/apiserver/controllers/jobs.go:2464-2620 (ControlJobByID): the backend.ControlJob loop over successJobs is inside the per-selection loop.
  2. Live: submit two sleep 300 jobs A and B; xcecli jobs stop A,B; the controller log shows the stop for A twice.
  • Frequency: deterministic (by code reading; not yet run)
  • Evidence: not kept (code reading only)

Root cause

In ControlJobByID (src/frontend/apiserver/controllers/jobs.go), successJobs was declared once outside the loop over the request's selections and appended to inside it, while the backend.ControlJob dispatch loop over the whole accumulated slice also sat inside the per-selection loop. Every later selection therefore re-dispatched all jobs collected for earlier selections, and the response was built from the accumulated slice.

Fix

Task 7.4 of spec job-array-one-based-index restructures the handler: all selections are validated before any store access; the selection loop only collects the jobs to act on (de-duplicated by unique_job_id) and the per-number not-found results; after the loop each job is validated once with validateJobControl and each accepted job is dispatched exactly once through controlJob.

Verification

  • Test: TestJobHandler_ControlTwoSelectionsDispatchOnce in src/frontend/apiserver/controllers/jobs_handler_test.go: RED before (X[1],Y[2] dispatched [x1 x1 x1 x1 y2 y2]; A,B dispatched [A A A A B B]), GREEN after ([x1 y2], [A B])
  • Suites: apiserver non-cgo unit tests (controllers, store, utils, backend) and the cgo build via xce-build.sh apiserver asan build.jai, all passing, 2026-10-01
  • Live: n/a here; the live REST control flow is exercised in task 10.2 of the spec

References

  • Related: bug-1898 (same review), bug-1896 (spec job-array-one-based-index restructures this handler)