Skip to content

perf(jobworker): cache claim prepared statement and add claim index - #8

Merged
ungerik merged 3 commits into
mainfrom
ungerik/optimize-registered-job-types
Jun 18, 2026
Merged

ungerik merged 3 commits into
mainfrom
ungerik/optimize-registered-job-types

Conversation

@ungerik

@ungerik ungerik commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Optimizes the hot StartNextJobOrNil claim path: it claims and starts the next job in a single cached CTE prepared statement (re-prepared only on Register/Unregister) with registered job types inlined as SQL literals, backed by a new partial worker_job_claim_idx index, and stamps started_at/updated_at/worker_alive_at from the database clock for clock-skew immunity. BREAKING: jobworker.RegisteredJobTypes() now returns (jobTypes []string, generation uint64) — a cached, sorted, shared slice that must not be mutated — instead of notnull.StringArray. Registration (Register/RegisterFunc/RegisterFuncForJobType/Unregister) is now startup-only and panics if called while worker threads are running. Adds unit tests (job/jobbundle/jobtype/status, reflection-based registerFunc, context helpers) plus DB integration tests covering every previously-untested jobworkerdb query, delete, and closed-service method. Also adds revive/gosec lint tooling (pinned in tools/go.mod, run by run-tests.sh before tests), makes the test run cover ./..., bumps the Go toolchain to 1.26 (go.mod + CI), and updates the go-sqldb/go-errs/golog/go-types dependencies.

Releases as v0.7.0 (minor bump from v0.6.0, for the breaking RegisteredJobTypes() change). Existing databases must add the new claim index out-of-band — see the migration in CHANGELOG.md.

Documentation

  • README.md — documents the startup-only registration rule, the HeartbeatInterval immutability constraint (set before StartThreads), the optional worker_job_claim_idx migration, and the refreshed test workflow (static analysis via go vet/revive/gosec, -s to skip, go test ./...).
  • CLAUDE.md — test commands, the startup-only registration panic, the single-active-service caveat, and HeartbeatInterval immutability.
  • CHANGELOG.md — v0.7.0 entry: the new claim index, the single-CTE cached claim statement, database-clock timestamps, the breaking RegisteredJobTypes() change, the registration panic, the Go 1.26 toolchain bump, dependency updates, and the index migration SQL.
  • schema/worker/job.sql — claim-index comment.

No outstanding documentation debt: every new public surface (worker_job_claim_idx, the RegisteredJobTypes() change, the registration panic, HeartbeatInterval immutability, the single-active-service caveat) is covered in the docs above and in godoc.

ungerik and others added 3 commits June 18, 2026 14:19
Optimize the StartNextJobOrNil claim path: claim and start the next job
in a single CTE prepared statement (cached, re-prepared only on
Register/Unregister) with registered job types inlined as SQL literals,
backed by a new partial claim index worker_job_claim_idx. Claim
timestamps now use the database clock (now()) for clock-skew immunity.

RegisteredJobTypes() returns a cached, sorted, shared slice plus a
generation counter so consumers rebuild only when it changes.

Add unit tests (job/jobbundle/jobtype/status, registerFunc, context) and
DB integration tests covering all previously-untested jobworkerdb query,
delete, and closed-service methods. run-tests.sh now runs ./... and the
Go toolchain is bumped to 1.26.

BREAKING CHANGE: jobworker.RegisteredJobTypes() now returns
(jobTypes []string, generation uint64) instead of notnull.StringArray;
the returned slice is shared and must not be mutated.
Pin revive and gosec in a separate tools/go.mod and run go vet, revive
(revive.toml), and gosec before the tests in run-tests.sh.

Fix the reported findings:
- service.go: omit the inferred Service type from the defaultService var
- jobworker: rename a clear closure that shadowed the builtin
- jobworker: use errs.New instead of fmt.Errorf for a non-formatted message

In tests, call t.Context() directly instead of aliasing it to ctx, and
have test helpers derive t.Context() internally rather than taking a
context parameter (also resolves revive's context-as-argument).
Bump VERSION to v0.7.0 (minor) for the breaking RegisteredJobTypes signature
change. Sync README, CLAUDE.md, and CHANGELOG with what shipped: the
startup-only registration panic, HeartbeatInterval immutability, the
single-active-service caveat, the static-analysis test step (go vet/revive/gosec,
-s flag, go test ./...), the Go 1.26.0 toolchain bump, and a precision fix to the
worker_job_claim_idx ordering claim (per-type merge, not a global no-sort scan).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ungerik
ungerik merged commit e938ce0 into main Jun 18, 2026
2 checks passed
@ungerik
ungerik deleted the ungerik/optimize-registered-job-types branch July 29, 2026 18:12
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