Bug
A scheduled job whose runner returns { ok: false, error } (rather than throwing) was recorded as SUCCESS in PipelineLog and JobLastRun. The scheduler only branched on a thrown exception; a soft-failure return value fell through to the success path.
Concretely for semaphore-tag-sync: a fail-shut fetch/mapping error returns { ok:false, error } by design (so nothing is written), yet the run showed green — masking that the taxonomy import silently did nothing. This is why the "no new tags imported" prod symptom was invisible in the run history.
Fix (in this PR)
srv/jobs/scheduler.js now inspects the runner's return value after fn(logId):
result && typeof result === 'object' && result.ok === false → outcome error, logPipelineEnd(logId, 'FAILED', summary, errorMessage), and a ScheduledJobFailed alert is raised.
- otherwise →
logPipelineEnd(logId, 'SUCCESS', summary) as before.
errorMessage derives from result.error when present, else <jobName> returned ok:false.
Acceptance
- A runner returning
{ok:false} produces a FAILED PipelineLog row with the error in the error column (arg 4 of logPipelineEnd, not the summary column) and a failed JobLastRun.
- A thrown exception still fails as before.
- A runner returning
{ok:true} (or a plain summary) still succeeds.
- Covered by the scheduler unit suite.
Ref: #2184.
Bug
A scheduled job whose runner returns
{ ok: false, error }(rather than throwing) was recorded as SUCCESS inPipelineLogandJobLastRun. The scheduler only branched on a thrown exception; a soft-failure return value fell through to the success path.Concretely for semaphore-tag-sync: a fail-shut fetch/mapping error returns
{ ok:false, error }by design (so nothing is written), yet the run showed green — masking that the taxonomy import silently did nothing. This is why the "no new tags imported" prod symptom was invisible in the run history.Fix (in this PR)
srv/jobs/scheduler.jsnow inspects the runner's return value afterfn(logId):result && typeof result === 'object' && result.ok === false→ outcomeerror,logPipelineEnd(logId, 'FAILED', summary, errorMessage), and aScheduledJobFailedalert is raised.logPipelineEnd(logId, 'SUCCESS', summary)as before.errorMessagederives fromresult.errorwhen present, else<jobName> returned ok:false.Acceptance
{ok:false}produces a FAILEDPipelineLogrow with the error in the error column (arg 4 oflogPipelineEnd, not the summary column) and a failedJobLastRun.{ok:true}(or a plain summary) still succeeds.Ref: #2184.