diff --git a/src/frontend/apiserver/models/jobs.go b/src/frontend/apiserver/models/jobs.go index 772cf33e..f730491b 100644 --- a/src/frontend/apiserver/models/jobs.go +++ b/src/frontend/apiserver/models/jobs.go @@ -61,18 +61,19 @@ var JobSignalMapTable = map[string]int{ } var JOBSTAT = map[string]int{ - "PEND": 0x01, - "RUN": 0x02, - "EXIT": 0x04, - "DONE": 0x08, - "PSUSP": 0x10, - "USUSP": 0x20, - "SSUSP": 0x40, - "PDONE": 0x80, - "PERR": 0x100, - "WAIT": 0x200, - "RUNKWN": 0x8000, - "UNKNOWN": 0x10000, // C JOB_STAT_UNKWN: worker lost contact with controller + "PEND": 0x01, + "RUN": 0x02, + "EXIT": 0x04, + "DONE": 0x08, + "PSUSP": 0x10, + "USUSP": 0x20, + "SSUSP": 0x40, + "PDONE": 0x80, + "PERR": 0x100, + "WAIT": 0x200, + "TRANSIENT": 0x400, // C JOB_STAT_TRANSIENT: job state uncertain after failover + "RUNKWN": 0x8000, + "UNKNOWN": 0x10000, // C JOB_STAT_UNKWN: worker lost contact with controller } var LAUNCHTYPE = map[string]int{ @@ -81,7 +82,10 @@ var LAUNCHTYPE = map[string]int{ } func JobStateStr(state int) string { - if (state & JOBSTAT["PEND"]) != 0 { + // Check TRANSIENT first — it takes priority after failover + if (state & JOBSTAT["TRANSIENT"]) != 0 { + return "TRANSIENT" + } else if (state & JOBSTAT["PEND"]) != 0 { if (state & JOBSTAT["PSUSP"]) != 0 { return "PSUSP" } diff --git a/src/frontend/apiserver/models/jobs_test.go b/src/frontend/apiserver/models/jobs_test.go index d4a7b794..4806aa70 100644 --- a/src/frontend/apiserver/models/jobs_test.go +++ b/src/frontend/apiserver/models/jobs_test.go @@ -58,6 +58,16 @@ func TestJobStateStr(t *testing.T) { state: 0, want: "ERR", }, + { + name: "TRANSIENT (0x400 — job uncertain after failover)", + state: 0x400, + want: "TRANSIENT", + }, + { + name: "TRANSIENT with other bits set", + state: 0x400 | 0x01, // TRANSIENT + PEND + want: "TRANSIENT", + }, } for _, tt := range tests { @@ -73,18 +83,19 @@ func TestJobStateStr(t *testing.T) { func TestJobStatMapValues(t *testing.T) { // Verify bitmask values match C JOB_STAT_* defines in src/include/xce/types.h. expected := map[string]int{ - "PEND": 0x01, - "RUN": 0x02, - "EXIT": 0x04, - "DONE": 0x08, - "PSUSP": 0x10, - "USUSP": 0x20, - "SSUSP": 0x40, - "PDONE": 0x80, - "PERR": 0x100, - "WAIT": 0x200, - "RUNKWN": 0x8000, - "UNKNOWN": 0x10000, + "PEND": 0x01, + "RUN": 0x02, + "EXIT": 0x04, + "DONE": 0x08, + "PSUSP": 0x10, + "USUSP": 0x20, + "SSUSP": 0x40, + "PDONE": 0x80, + "PERR": 0x100, + "WAIT": 0x200, + "TRANSIENT": 0x400, + "RUNKWN": 0x8000, + "UNKNOWN": 0x10000, } for key, want := range expected { got, ok := JOBSTAT[key]