Skip to content

#131 Refactor JobStore decorators onto a shared forwarding base - #134

Merged
hemju merged 1 commit into
mainfrom
issue-131-forwarding-job-store
Sep 4, 2026
Merged

#131 Refactor JobStore decorators onto a shared forwarding base#134
hemju merged 1 commit into
mainfrom
issue-131-forwarding-job-store

Conversation

@hemju

@hemju hemju commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Closes #131.

Problem

Threadmill had three hand-written full-JobStore forwarding decorators: the test-support ForwardingJobStore, TracingJobStore, and MeteredJobStore. The SPI's default methods never produce a compiler failure when a decorator forgets to forward them, and TracingJobStore implemented JobStore directly and missed supportsExternalTransactions() and createRemoteWakeChannel(String). A traced PostgreSQL store therefore reported no external-transaction support (join_transaction unavailable) and no LISTEN/NOTIFY wake channel.

Change

  • com.hemju.threadmill.core.store.ForwardingJobStore (new, threadmill-core): forwards every SPI operation, the interface defaults included. delegate() is final and always returns the immediate delegate, so the Spring auto-config's unwrap loop still walks a chain one layer at a time.
  • TracingJobStore and MeteredJobStore now extend the base and override only what they instrument. The metrics decorator drops 24 pure forwards; tracing keeps a span per I/O operation and inherits the capability reads without a span.
  • com.hemju.threadmill.test.ForwardingJobStore becomes a deprecated alias for the core class (test-support is a published artifact); every in-repo usage moved to the core class.
  • JobStoreDecoratorContract.assertForwardsEveryOperation (new, threadmill-test-support): wraps a recording Proxy, enumerates JobStore.class.getMethods() by reflection, and requires each method to reach the delegate exactly once with the caller's arguments and to return the delegate's result. Because the method list comes from reflection, an SPI method added later is covered automatically; a new parameter/return type fails loudly until a sample is added.
  • The shared AbstractJobStoreContractTest now also runs through the plain base (ForwardingJobStoreContractTest) and the tracing decorator (TracingJobStoreContractTest), alongside the existing MeteredJobStoreContractTest.
  • Named regressions for external-transaction and remote-wake forwarding on the base, tracing, and metrics decorators, plus a red-path test proving the reflective check fails by method name on an unforwarded default.
  • threadmill-tracing gains a testImplementation dependency on threadmill-test-support; its gradle.lockfile picks up awaitility/hamcrest on the test classpaths (already in verification-metadata.xml).
  • Docs: AGENTS.md decision + regression-matrix row, CHANGELOG.md (Unreleased), test-support and tracing READMEs.

Verification

  • ./gradlew check green (all modules, Spotless included).

Move the full-SPI forwarding decorator into threadmill-core as
com.hemju.threadmill.core.store.ForwardingJobStore and make TracingJobStore
and MeteredJobStore extend it, overriding only the operations they
instrument. The interface's default methods never produce a compiler
failure when a decorator forgets to forward them; TracingJobStore missed
supportsExternalTransactions() and createRemoteWakeChannel(String), so a
traced PostgreSQL store lost join_transaction support and its LISTEN/NOTIFY
wake channel behind the decorator.

The test-support ForwardingJobStore becomes a deprecated alias. New
JobStoreDecoratorContract.assertForwardsEveryOperation enumerates
JobStore's methods by reflection against a recording proxy so a future SPI
addition that falls through to a default fails by name; the shared store
contract now also runs through the plain base and the tracing decorator,
with named external-transaction and remote-wake regressions on all three.

Closes #131
@hemju
hemju merged commit 48b5d3c into main Sep 4, 2026
3 checks passed
@hemju
hemju deleted the issue-131-forwarding-job-store branch September 10, 2026 05:40
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.

Refactor JobStore decorators onto a shared forwarding base

1 participant