Skip to content

feat(api): add include=last_run to job reads - #1

Merged
BK1031 merged 1 commit into
mainfrom
bk1031/last-run-include
Aug 7, 2026
Merged

feat(api): add include=last_run to job reads#1
BK1031 merged 1 commit into
mainfrom
bk1031/last-run-include

Conversation

@BK1031

@BK1031 BK1031 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
  • Add service.LastRun(jobID) — newest attempt whatever its status, nil when never claimed
  • Add service.LastRunsForJobs(ids) — batched via DISTINCT ON (job_id) ... ORDER BY job_id, attempt DESC, one query per list
  • Parse ?include= as a comma-separated set in GetJob and ListJobs; unknown values ignored so adding more later can't break existing clients
  • Add last_run to the jobWithRun response as omitempty, so include=current_run responses stay byte-identical
  • SSE buildJobEvent now serves both fields from one LastRun lookup — the newest attempt is the in-flight one whenever a job is running, so current_run keeps its exact meaning
  • Go client: Job.LastRun field and JobsFilter.IncludeLastRun, which builds the comma-separated param
  • Tests for the cases CurrentRun can't serve: survives a failed attempt, returns the highest attempt, one row per job, absent when never claimed

Why

CurrentRun filters status = 'running' (service/job.go:504, :665), and run/job transitions are atomic — Fail/Complete are transactional and the reaper is a single CTE. So current_run is non-null iff the job is active, leaving pending-after-retry and terminal jobs with no run data.

That means consumers can't see where a failed attempt got to, or read a partial result a handler attached to a failure via FailRequest.Result. The Mapache dashboard's jobs list has dead code built on the assumption that this already worked.

Notes

  • GetJob's Go-client signature still takes a single includeCurrentRun bool. Left alone to stay source-compatible; worth widening if a Go consumer needs last_run from a single-job read.
  • gofmt -l flags api/job.go, which it also does on clean main (the comment inside failRequest splits the struct's alignment group). Not touched here.

Test plan

  • go test ./... green, including 5 new cases against real Postgres via testcontainers
  • go build ./... and go vet ./... clean

current_run only ever matches a running attempt, so pending-after-retry
and terminal jobs carry no run data at all — consumers can't show where
a failed attempt got to, or read the partial result a handler returned
alongside its error.

Add a last_run include that returns the newest attempt whatever its
status, batched with DISTINCT ON so a jobs-list expansion stays one
query. ?include= now parses as a comma-separated set, ignoring unknown
values, so current_run keeps working unchanged and both can be asked for
at once. last_run is omitempty, leaving existing current_run responses
byte-identical.

SSE serves both from a single LastRun lookup: the newest attempt is the
in-flight one whenever a job is running, so current_run keeps its exact
meaning while last_run also survives terminalization.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b45acae9f4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread api/job.go
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
out := jobWithRun{Job: job}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Omit current_run when it was not requested

For GET /jobs/:id?include=last_run, constructing jobWithRun here leaves CurrentRun nil, but its JSON field lacks omitempty, so the response unexpectedly contains "current_run": null; the list path has the same behavior. This breaks the new set-like include semantics and prevents clients from distinguishing an unrequested expansion from a requested current run that does not exist. Use conditional response shapes or marshaling so current_run remains present and nullable only when current_run was requested.

Useful? React with 👍 / 👎.

@BK1031
BK1031 merged commit 7cf2380 into main Aug 7, 2026
4 checks passed
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.

1 participant