mirror of
https://github.com/hansjone/dsh-ops-cron.git
synced 2026-10-09 00:43:22 +08:00
Preserve run start timestamps when settling terminal status.
cron_runs entered/exited were identical because settleRun rewrote stateEnteredAt and actualAt to the finish instant. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
6ed7187754
commit
8cc3bed5f1
2 changed files with 37 additions and 7 deletions
11
lib/fire.js
11
lib/fire.js
|
|
@ -252,13 +252,14 @@ export function settleRun(state, runId, terminal, now) {
|
|||
const status = terminal?.status && !ACTIVE_RUN_STATUSES.has(terminal.status)
|
||||
? terminal.status
|
||||
: 'succeeded'
|
||||
const prevStatus = run.status
|
||||
// Keep stateEnteredAt / actualAt from queued→running so cron_runs duration is real.
|
||||
// Only stamp exitedAt (and lastRunAt on the job) at settle time.
|
||||
let next = patchRun(state, runId, {
|
||||
status,
|
||||
summary: terminal?.summary || '',
|
||||
error: terminal?.error || null,
|
||||
actualAt: now,
|
||||
stateEnteredAt: prevStatus === status ? (run.stateEnteredAt || now) : now,
|
||||
actualAt: run.actualAt || now,
|
||||
stateEnteredAt: run.stateEnteredAt || run.actualAt || now,
|
||||
exitedAt: now,
|
||||
sessionId: run.sessionId,
|
||||
...terminal?.outputRef ? { outputRef: terminal.outputRef } : {},
|
||||
|
|
@ -389,8 +390,8 @@ export function interruptActiveRuns(state, now, reason = 'host_interrupted') {
|
|||
status: 'failed',
|
||||
error: reason,
|
||||
summary: 'Host stopped before this run finished',
|
||||
actualAt: now,
|
||||
stateEnteredAt: now,
|
||||
actualAt: run.actualAt || now,
|
||||
stateEnteredAt: run.stateEnteredAt || run.actualAt || now,
|
||||
exitedAt: now,
|
||||
})
|
||||
const job = getJob(next, run.jobId)
|
||||
|
|
|
|||
|
|
@ -15,11 +15,40 @@ import {
|
|||
selectJobsByWatch,
|
||||
} from '../lib/monitor.js'
|
||||
import { createJobRecord, emptyState, listHistoryPage, pruneRuns } from '../lib/store.js'
|
||||
import { claimOccurrence, publicJob } from '../lib/fire.js'
|
||||
import { claimOccurrence, publicJob, settleRun } from '../lib/fire.js'
|
||||
import { createHostService } from '../lib/host.js'
|
||||
import { cronToolDefinitions } from '../lib/tools.js'
|
||||
|
||||
test('labelsMatch any/all', () => {
|
||||
test('settleRun keeps running enter time and stamps exitedAt separately', () => {
|
||||
const now = Date.parse('2026-09-10T07:00:00.000Z')
|
||||
const started = now - 60_000
|
||||
let state = emptyState()
|
||||
const job = createJobRecord({
|
||||
name: 'dur',
|
||||
prompt: 'x',
|
||||
schedule: { kind: 'at', at: new Date(now + 60_000).toISOString(), timezone: 'Asia/Shanghai' },
|
||||
}, state, now)
|
||||
state = { ...state, jobs: [job], runs: [{
|
||||
id: 'r1',
|
||||
jobId: job.id,
|
||||
status: 'running',
|
||||
scheduledAt: started,
|
||||
actualAt: started,
|
||||
stateEnteredAt: started,
|
||||
exitedAt: null,
|
||||
summary: '',
|
||||
error: null,
|
||||
sessionId: 's1',
|
||||
}] }
|
||||
state = settleRun(state, 'r1', { status: 'succeeded', summary: 'ok' }, now)
|
||||
const run = state.runs.find((row) => row.id === 'r1')
|
||||
assert.equal(run.status, 'succeeded')
|
||||
assert.equal(run.stateEnteredAt, started)
|
||||
assert.equal(run.actualAt, started)
|
||||
assert.equal(run.exitedAt, now)
|
||||
assert.ok(run.exitedAt > run.stateEnteredAt)
|
||||
})
|
||||
|
||||
const job = { role: 'worker', task: 'theory', owner: 'alice' }
|
||||
assert.equal(labelsMatch(job, { role: 'worker', task: 'theory' }, 'all'), true)
|
||||
assert.equal(labelsMatch(job, { role: 'worker', owner: 'bob' }, 'all'), false)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue