diff --git a/AGENTS.md b/AGENTS.md
index 4a22e7787..6c017ca48 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -40,6 +40,13 @@ This repo holds the Go reference implementation and its ports (`java/`, `js/`, `
- **Same tests everywhere**: give each affected implementation an equivalent test for the behavior, on every database it supports.
- **Document intended differences**: an API should be idiomatic for its language, but observable behavior should match Go. Record any difference that remains in the port's differences doc (for example `java/DIFFERENCES.md`).
+## Commit and PR Titles
+
+- When a change affects only a subset of the languages, prefix the PR title and commit subjects with the affected languages in lowercase brackets: `[java]`, `[go]`, or `[go, ruby]`.
+- Use `go`, `java`, `js`, `ruby`, and `rust` as the language names. List multiple languages alphabetically, separated by a comma and a space.
+- Avoid repeating the language names in the rest of the title when the prefix already makes the scope clear. For example, use `[java] Enforce warning-free builds` instead of `[java] Enforce warning-free Java builds`.
+- Omit the prefix for changes that affect all languages or are independent of any particular language, such as repository-wide contributor guidance.
+
## Package Naming and Organization
- Package names are lowercase, short, and representative; avoid `common`, `util`, or overly broad names.
diff --git a/Makefile b/Makefile
index 867bdf544..b4f16f969 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,7 @@
SQLC ?= sqlc
MVN ?= mvn
+java_mvn = ./java/bin/check-maven-warnings.sh $(MVN) --batch-mode --no-transfer-progress -Dstyle.color=never
.PHONY: check/modzip
check/modzip: ## Check that no Go module zip includes fixtures, testdata, or another language's port
@@ -117,12 +118,12 @@ lint/rust: ## Run Rust formatting and clippy checks, including single-backend bu
# Java targets stay separate so Go-only contributors do not need a JDK or Maven.
.PHONY: build/java
build/java: ## Build the Java library, CLI, and development adapter (JDK 21+)
- $(MVN) --batch-mode --no-transfer-progress -f java/pom.xml package -DskipTests
+ $(java_mvn) -f java/pom.xml package -DskipTests
.PHONY: lint/java
lint/java: ## Compile Java, check formatting, and lint Go maintenance tools
lint/java: lint/java/tools
- $(MVN) --batch-mode --no-transfer-progress -f java/pom.xml verify -DskipTests
+ $(java_mvn) -f java/pom.xml verify -DskipTests
# Java's module boundary excludes it from Go package discovery. Pass the tool
# files explicitly so they use this workspace's Go version and test dependencies.
@@ -172,27 +173,28 @@ RUST_POSTGRES_TESTS_ENV = RUSTFLAGS="$$RUSTFLAGS --cfg river_postgres_tests" \
test/java: ## Run Java tests, executable CLI tests, and formatting checks
test/java: generate/fixtures verify/java-migrations
test/java: test/java/tools
- $(MVN) --batch-mode --no-transfer-progress -f java/pom.xml verify
+ $(java_mvn) -f java/pom.xml verify
# Fixture comparisons use temporary SQLite databases, with no Postgres or legacy adapter.
.PHONY: test/java/conformance
test/java/conformance: ## Run Java tests that check Go-generated conformance fixtures
test/java/conformance: generate/fixtures
- $(MVN) --batch-mode --no-transfer-progress -f java/pom.xml -pl river test -Dgroups=conformance -Driver.test.database=sqlite
+ $(java_mvn) -f java/pom.xml -pl river test -Dgroups=conformance -Driver.test.database=sqlite
.PHONY: test/java/postgres
test/java/postgres: ## Run Java tests with Postgres client and worker coverage (requires RIVER_TEST_DATABASE_URL)
test/java/postgres: generate/fixtures verify/java-migrations
@test -n "$$RIVER_TEST_DATABASE_URL" || { echo "RIVER_TEST_DATABASE_URL is required" >&2; exit 1; }
- $(MVN) --batch-mode --no-transfer-progress -f java/pom.xml verify -Driver.test.database=postgres
+ $(java_mvn) -f java/pom.xml verify -Driver.test.database=postgres
.PHONY: test/java/sqlite
test/java/sqlite: ## Run Java unit, SQLite, and executable CLI tests without Postgres
test/java/sqlite: generate/fixtures verify/java-migrations
- $(MVN) --batch-mode --no-transfer-progress -f java/pom.xml verify -Driver.test.database=sqlite -DexcludedGroups=postgres
+ $(java_mvn) -f java/pom.xml verify -Driver.test.database=sqlite -DexcludedGroups=postgres
.PHONY: test/java/tools
-test/java/tools: ## Test Java's Go maintenance tools
+test/java/tools: ## Test Java maintenance tools and Maven warning enforcement
+ bash java/bin/check-maven-warnings_test.sh
go test ./java/bin/check-packages/*.go
go test ./java/bin/sync-migrations/*.go
diff --git a/java/bin/check-maven-warnings.sh b/java/bin/check-maven-warnings.sh
new file mode 100755
index 000000000..3bc2253fd
--- /dev/null
+++ b/java/bin/check-maven-warnings.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+# Maven 3 has no general fail-on-warning option. Keep its output visible, then
+# reject warnings from packaging and other plugins as well as the compiler.
+set -euo pipefail
+
+maven_log=$(mktemp)
+trap 'rm -f "$maven_log"' EXIT
+
+"$@" 2>&1 | tee "$maven_log"
+
+if grep -q '^\[WARNING\]' "$maven_log"; then
+ echo 'Java build emitted Maven warnings; fix them or document an intentional suppression.' >&2
+ exit 1
+fi
diff --git a/java/bin/check-maven-warnings_test.sh b/java/bin/check-maven-warnings_test.sh
new file mode 100644
index 000000000..bb60c985d
--- /dev/null
+++ b/java/bin/check-maven-warnings_test.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
+test_dir=$(mktemp -d)
+trap 'rm -rf "$test_dir"' EXIT
+
+check() {
+ local name=$1 expected=$2 output=$3 message=$4
+ local actual=0
+ "$script_dir/check-maven-warnings.sh" bash -c "$output" >"$test_dir/output" 2>&1 || actual=$?
+ if [[ "$actual" -ne "$expected" ]]; then
+ cat "$test_dir/output" >&2
+ echo "$name: expected exit $expected, got $actual" >&2
+ exit 1
+ fi
+ if ! grep -Fq "$message" "$test_dir/output"; then
+ echo "$name: missing command output: $message" >&2
+ exit 1
+ fi
+}
+
+check clean 0 'echo "[INFO] BUILD SUCCESS"' '[INFO] BUILD SUCCESS'
+check warning_stdout 1 'echo "[WARNING] duplicate class"' '[WARNING] duplicate class'
+check warning_stderr 1 'echo "[WARNING] duplicate resource" >&2' '[WARNING] duplicate resource'
+check command_failure 23 'echo "[ERROR] build failed"; exit 23' '[ERROR] build failed'
+check failure_with_warning 17 'echo "[WARNING] warning before failure"; exit 17' '[WARNING] warning before failure'
+check ordinary_word 0 'echo "[INFO] test checks WARNING handling"' '[INFO] test checks WARNING handling'
+check application_log 0 'echo "WARNING: expected test log"' 'WARNING: expected test log'
+
+echo 'Maven warning enforcement checks passed'
diff --git a/java/cli/pom.xml b/java/cli/pom.xml
index 76e14a5ea..3746eb427 100644
--- a/java/cli/pom.xml
+++ b/java/cli/pom.xml
@@ -19,13 +19,17 @@
false
trueall
+
+ META-INF/LICENSE
+ META-INF/NOTICE
com.riverqueue.cli.MigrationCli
- ${project.version}ALL-UNNAMED
+ true${project.version}ALL-UNNAMED
- *:*META-INF/*.SFMETA-INF/*.DSAMETA-INF/*.RSAmodule-info.classMETA-INF/versions/*/module-info.class
+
+ *:*META-INF/MANIFEST.MFMETA-INF/*.SFMETA-INF/*.DSAMETA-INF/*.RSAmodule-info.classMETA-INF/versions/*/module-info.class
org.apache.maven.pluginsmaven-failsafe-plugin3.5.4
diff --git a/java/conformance/pom.xml b/java/conformance/pom.xml
index c03b1ac56..1e300d437 100644
--- a/java/conformance/pom.xml
+++ b/java/conformance/pom.xml
@@ -10,5 +10,28 @@
org.postgresqlpostgresql
org.xerialsqlite-jdbc
- org.apache.maven.pluginsmaven-shade-plugin3.6.1packageshadefalsecom.riverqueue.conformance.Adapter*:*META-INF/*.SFMETA-INF/*.DSAMETA-INF/*.RSA
+
+
+ org.apache.maven.pluginsmaven-shade-plugin3.6.1
+ packageshade
+ false
+
+
+ META-INF/LICENSE
+ META-INF/NOTICE
+
+
+ com.riverqueue.conformance.Adapter
+ true
+
+
+
+ *:*
+ META-INF/MANIFEST.MF
+ META-INF/*.SFMETA-INF/*.DSAMETA-INF/*.RSA
+ module-info.classMETA-INF/versions/*/module-info.class
+
+
+
+
diff --git a/java/docs/development.md b/java/docs/development.md
index 3c55228f2..eb8f58977 100644
--- a/java/docs/development.md
+++ b/java/docs/development.md
@@ -82,6 +82,25 @@ filtered to changes in Java, its build configuration, fixtures, and canonical
migrations. Go changes run the smaller fixture suite in the shared Conformance
workflow alongside Rust and JavaScript.
+## Warning policy
+
+Java builds keep `-Xlint:all` enabled and fail on unsuppressed compiler warnings,
+including test compilation. Tests that intentionally hold workers or subscriptions
+open for a block use a method-level `@SuppressWarnings("try")` with a short reason.
+Other compiler diagnostics remain enabled.
+
+The Make targets run Maven through `bin/check-maven-warnings.sh`. It streams the
+complete build output, preserves command failures, and rejects Maven warning
+messages from packaging and other plugins. Local checks and CI use these same
+targets. Direct Maven invocations also reject compiler warnings through the
+parent POM's `failOnWarning` setting.
+
+Executable JARs merge dependency `META-INF/LICENSE` and `META-INF/NOTICE` text,
+retain service registrations, and generate their own executable manifests.
+Dependency module descriptors and signatures are excluded from these combined
+archives. Other overlapping classes or resources still produce warnings and fail
+the checked Make targets. Library and source JARs keep their normal packaging.
+
## Legacy cross-process harness
The original interoperability adapter remains available for broader storage,
diff --git a/java/pom.xml b/java/pom.xml
index b858716ae..94aef9a28 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -20,7 +20,15 @@
org.apache.maven.pluginsmaven-jar-plugin3.5.1true
- org.apache.maven.pluginsmaven-compiler-plugin3.14.1truetrue-Xlint:all
+
+ org.apache.maven.pluginsmaven-compiler-plugin3.14.1
+
+ true
+ true
+ true
+ -Xlint:all
+
+
org.apache.maven.pluginsmaven-surefire-plugin3.5.4--enable-native-access=ALL-UNNAMED
org.apache.maven.pluginsmaven-source-plugin3.3.1jar-no-fork
com.diffplug.spotlessspotless-maven-plugin2.44.31.28.0verifycheck
diff --git a/java/river/src/test/java/com/riverqueue/ClientTest.java b/java/river/src/test/java/com/riverqueue/ClientTest.java
index aed0cd68b..dfb0d6e90 100644
--- a/java/river/src/test/java/com/riverqueue/ClientTest.java
+++ b/java/river/src/test/java/com/riverqueue/ClientTest.java
@@ -288,6 +288,7 @@ public void insertBegin(
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void fetchOnlyKnownKindsLeavesPeerJobsAvailable() throws Exception {
var river = database();
var peer = JobType.of("peer_only", Email.class);
@@ -523,6 +524,7 @@ public void insertBegin(
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void sqliteQueueNotificationFailureRollsBackQueueMutation() throws Exception {
var river =
new Client(
@@ -555,6 +557,7 @@ void sqliteQueueNotificationFailureRollsBackQueueMutation() throws Exception {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void committedCompletionWinsOverSubsequentHandlerFailure() throws Exception {
var river = database();
var event = new CompletableFuture();
@@ -585,6 +588,7 @@ void committedCompletionWinsOverSubsequentHandlerFailure() throws Exception {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void retryPolicyReceivesFailedAttemptSnapshot() throws Exception {
var river = database();
var observed = new CompletableFuture>();
@@ -623,6 +627,7 @@ void retryPolicyReceivesFailedAttemptSnapshot() throws Exception {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void jobKindLengthMatchesDatabaseConstraint() throws Exception {
var client = database();
var type = JobType.of("k".repeat(127), Email.class);
diff --git a/java/river/src/test/java/com/riverqueue/HookMiddlewareTest.java b/java/river/src/test/java/com/riverqueue/HookMiddlewareTest.java
index 727131840..cb47eda4b 100644
--- a/java/river/src/test/java/com/riverqueue/HookMiddlewareTest.java
+++ b/java/river/src/test/java/com/riverqueue/HookMiddlewareTest.java
@@ -176,6 +176,7 @@ void registrationRejectsNullEntries() {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void workBeginFailureSkipsHandlerAndEndHooks() throws Exception {
var trace = new ArrayList();
var river =
@@ -222,6 +223,7 @@ void workBeginFailureSkipsHandlerAndEndHooks() throws Exception {
"failure,replace",
"success,throw"
})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void workEndHooksChainOutcomesInsideMiddleware(String outcome, String action) throws Exception {
var trace = new ArrayList();
var failure = new IOException("handler failed");
diff --git a/java/river/src/test/java/com/riverqueue/NotificationCleanupTest.java b/java/river/src/test/java/com/riverqueue/NotificationCleanupTest.java
index 002a79db0..d7bc09a6a 100644
--- a/java/river/src/test/java/com/riverqueue/NotificationCleanupTest.java
+++ b/java/river/src/test/java/com/riverqueue/NotificationCleanupTest.java
@@ -54,6 +54,7 @@ void deletesOldestRowsInBoundedBatchesAndRetainsCutoff() {
@ParameterizedTest
@ValueSource(booleans = {false, true})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void leaderCleansNotificationsEvenWhenPluginOwnsJobCleaning(boolean pluginOwnsCleaning)
throws Exception {
var database = TestDatabase.sqlite(directory.resolve("river.db"));
diff --git a/java/river/src/test/java/com/riverqueue/NotificationTest.java b/java/river/src/test/java/com/riverqueue/NotificationTest.java
index 4e443cb92..a4718fc9f 100644
--- a/java/river/src/test/java/com/riverqueue/NotificationTest.java
+++ b/java/river/src/test/java/com/riverqueue/NotificationTest.java
@@ -21,6 +21,7 @@ class NotificationTest {
@TempDir Path directory;
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void sqliteListenerRecoversFromAnInitialDatabaseFailure() throws Exception {
var database = TestDatabase.sqlite(directory.resolve("river.db"));
var fail = new AtomicBoolean(true);
diff --git a/java/river/src/test/java/com/riverqueue/PeerCancellationTest.java b/java/river/src/test/java/com/riverqueue/PeerCancellationTest.java
index f2d5c590d..b0ef87333 100644
--- a/java/river/src/test/java/com/riverqueue/PeerCancellationTest.java
+++ b/java/river/src/test/java/com/riverqueue/PeerCancellationTest.java
@@ -138,6 +138,7 @@ else if (cause == WorkContext.Cancellation.SHUTDOWN) {
@ParameterizedTest
@ValueSource(strings = {"decode", "work"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void peerTimeoutInterruptsTheOwningWorker(String phase) throws Exception {
var entered = new CompletableFuture();
var interrupted = new CompletableFuture();
diff --git a/java/river/src/test/java/com/riverqueue/PluginTest.java b/java/river/src/test/java/com/riverqueue/PluginTest.java
index 0c4396744..e5d4dce97 100644
--- a/java/river/src/test/java/com/riverqueue/PluginTest.java
+++ b/java/river/src/test/java/com/riverqueue/PluginTest.java
@@ -94,6 +94,7 @@ void pluginRegistrationRetainsDuplicates() {
@ParameterizedTest
@ValueSource(booleans = {false, true})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void pluginsActivateAllJobInterfacesBeforeExplicitRegistrations(boolean pluginsFirst)
throws Exception {
var trace = new CopyOnWriteArrayList();
diff --git a/java/river/src/test/java/com/riverqueue/ProtocolStorageTest.java b/java/river/src/test/java/com/riverqueue/ProtocolStorageTest.java
index b5e3e0da1..47fdbc6fe 100644
--- a/java/river/src/test/java/com/riverqueue/ProtocolStorageTest.java
+++ b/java/river/src/test/java/com/riverqueue/ProtocolStorageTest.java
@@ -27,6 +27,7 @@ private Client client() {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void periodicMetadata() throws Exception {
var keys = Conformance.fixture("protocol_values.json").required("metadata_keys");
var client = client();
@@ -59,6 +60,7 @@ void periodicMetadata() throws Exception {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void rescueCountAndOutput() throws Exception {
var fixture = Conformance.fixture("protocol_values.json");
var keys = fixture.required("metadata_keys");
diff --git a/java/river/src/test/java/com/riverqueue/RescueTest.java b/java/river/src/test/java/com/riverqueue/RescueTest.java
index 26530af95..549d5448f 100644
--- a/java/river/src/test/java/com/riverqueue/RescueTest.java
+++ b/java/river/src/test/java/com/riverqueue/RescueTest.java
@@ -28,6 +28,7 @@ class RescueTest {
@ParameterizedTest
@ValueSource(strings = {"default", "disabled", "error", "override", "throw", "zero"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void pilotReceivesWorkerTimeoutCallback(String mode) throws Exception {
var request = new CompletableFuture();
var errors = new LinkedBlockingQueue();
@@ -198,6 +199,7 @@ public void work(WorkContext context) {
@ParameterizedTest
@ValueSource(booleans = {false, true})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void rescueHonorsWorkerTimeouts(boolean defaultDisabled) throws Exception {
var maintained = new CompletableFuture();
var errors = new LinkedBlockingQueue();
@@ -293,6 +295,7 @@ public void work(WorkContext context) {
@ParameterizedTest
@ValueSource(strings = {"local", "peer", "peer_claim_retry", "peer_notification_retry"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void shortRescuedRetriesWakeFetchingBeforeMaintenance(String mode) throws Exception {
boolean peer = !mode.equals("local");
var database = databases.open(directory.resolve("river.db"));
diff --git a/java/river/src/test/java/com/riverqueue/ResumableTest.java b/java/river/src/test/java/com/riverqueue/ResumableTest.java
index f8106a545..08349069a 100644
--- a/java/river/src/test/java/com/riverqueue/ResumableTest.java
+++ b/java/river/src/test/java/com/riverqueue/ResumableTest.java
@@ -32,6 +32,7 @@ class ResumableTest {
"true,true,false",
"true,true,true"
})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void checkpointCommitsWithApplicationWrites(
boolean priorCheckpoint, boolean rollback, boolean withCursor) throws Exception {
var client = new Client(databases.open(directory.resolve("river.db")));
@@ -238,6 +239,7 @@ void checkpointRetainsOnlyCommittedProgress(boolean rollback, boolean finishStep
@ParameterizedTest
@ValueSource(strings = {"plain", "cursor", "null", "first", "first_null"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void cursorDoesNotCompleteFailedSteps(String mode) throws Exception {
var client = new Client(databases.open(directory.resolve("river.db")));
var events = new LinkedBlockingQueue();
@@ -327,6 +329,7 @@ void cursorInFirstStepIsBufferedAndNestedStepsAreRejected() throws Exception {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void cursorMapsReplaceCompletedStepsAndPreserveNullValues() throws Exception {
var client = new Client(databases.open(directory.resolve("river.db")));
var events = new LinkedBlockingQueue();
diff --git a/java/river/src/test/java/com/riverqueue/RetryTest.java b/java/river/src/test/java/com/riverqueue/RetryTest.java
index 52385d523..30f9bdd73 100644
--- a/java/river/src/test/java/com/riverqueue/RetryTest.java
+++ b/java/river/src/test/java/com/riverqueue/RetryTest.java
@@ -69,6 +69,7 @@ void retryNotifiesOnlyWhenTheRowChanges(Job.State state) {
@ParameterizedTest
@ValueSource(strings = {"local", "peer", "transaction"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void retryWakesWorkersAfterCommit(String mode) throws Exception {
var database = databases.open(directory.resolve("river.db"));
var warmed = new CompletableFuture();
diff --git a/java/river/src/test/java/com/riverqueue/SchedulingTest.java b/java/river/src/test/java/com/riverqueue/SchedulingTest.java
index 0d3e565da..d2e752ef6 100644
--- a/java/river/src/test/java/com/riverqueue/SchedulingTest.java
+++ b/java/river/src/test/java/com/riverqueue/SchedulingTest.java
@@ -31,6 +31,7 @@ class SchedulingTest {
@TempDir Path directory;
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void anonymousPeriodicJobsOmitTheIdMetadata() throws Exception {
var client = new Client(databases.open(directory.resolve("river.db")));
var worked = new CompletableFuture>();
@@ -228,6 +229,7 @@ public void maintain(Client client, Instant now) {
@ParameterizedTest
@ValueSource(strings = {"initial schedule", "following schedule", "insertion"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void failedPeriodicJobDoesNotBlockMaintenanceOrOtherJobs(String failurePoint) throws Exception {
var errors = new LinkedBlockingQueue();
var worked = new LinkedBlockingQueue();
@@ -285,6 +287,7 @@ public void afterInsert(
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void failedScheduleDoesNotInsertTheOccurrenceTwice() throws Exception {
var calls = new AtomicInteger();
var maintained = new CompletableFuture();
@@ -330,6 +333,7 @@ public void maintain(Client client, Instant now) {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void periodicSchedulesKeepTheirPlannedCadence() throws Exception {
var inserted = new AtomicReference>();
var client =
@@ -377,6 +381,7 @@ public void afterInsert(
@ParameterizedTest
@ValueSource(booleans = {false, true})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void periodicSchedulesUseTheSystemTimeZone(boolean runOnStart) throws Exception {
var original = TimeZone.getDefault();
var zone = ZoneId.of("Asia/Kolkata");
diff --git a/java/river/src/test/java/com/riverqueue/TimeoutTest.java b/java/river/src/test/java/com/riverqueue/TimeoutTest.java
index 76ed0815f..0cd4ac3c3 100644
--- a/java/river/src/test/java/com/riverqueue/TimeoutTest.java
+++ b/java/river/src/test/java/com/riverqueue/TimeoutTest.java
@@ -20,6 +20,7 @@ class TimeoutTest {
@ParameterizedTest
@ValueSource(strings = {"inherit", "override", "disabled", "longer", "zero", "overflow", "throw"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void handlerTimeoutControlsTheAttempt(String mode) throws Exception {
var client = new Client(databases.open(directory.resolve("river.db")));
var calls = new AtomicInteger();
diff --git a/java/river/src/test/java/com/riverqueue/VirtualThreadTest.java b/java/river/src/test/java/com/riverqueue/VirtualThreadTest.java
index 081488b3f..dfe2d8aed 100644
--- a/java/river/src/test/java/com/riverqueue/VirtualThreadTest.java
+++ b/java/river/src/test/java/com/riverqueue/VirtualThreadTest.java
@@ -61,6 +61,7 @@ private void probe(String scenario) throws Exception {
}
public static final class Probe {
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
public static void main(String[] args) throws Exception {
var entered = new CountDownLatch(1);
var release = new CountDownLatch(1);
diff --git a/java/river/src/test/java/com/riverqueue/WorkersTest.java b/java/river/src/test/java/com/riverqueue/WorkersTest.java
index b75176dd9..2d54db34b 100644
--- a/java/river/src/test/java/com/riverqueue/WorkersTest.java
+++ b/java/river/src/test/java/com/riverqueue/WorkersTest.java
@@ -73,6 +73,7 @@ void builderRequiresServiceIntervalsBelowQueueRetention(String value, boolean va
@ParameterizedTest
@CsvSource({"REMOTE,false", "REMOTE,true", "TIMEOUT,false", "TIMEOUT,true"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void cancellationRespectsTheHandlersOutcome(WorkContext.Cancellation cause, boolean interrupted)
throws Exception {
var client = client();
@@ -119,6 +120,7 @@ void cancellationRespectsTheHandlersOutcome(WorkContext.Cancellation cause, bool
@EnumSource(
value = Job.State.class,
names = {"AVAILABLE", "PENDING", "RETRYABLE", "RUNNING", "SCHEDULED"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void completionEventsReflectPersistedState(Job.State state) throws Exception {
var client = client();
var database = client.database();
@@ -176,6 +178,7 @@ void completionEventsReflectPersistedState(Job.State state) throws Exception {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void completionRetriesSurviveAnInterruptedHandler() throws Exception {
var attempts = new AtomicInteger();
var client =
@@ -215,6 +218,7 @@ public void afterAttempt(
@ParameterizedTest
@ValueSource(strings = {"args", "kind", "row"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void completionRetriesSurviveInvalidJobs(String invalid) throws Exception {
var attempts = new AtomicInteger();
var client =
@@ -288,6 +292,7 @@ public java.util.List claim(
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void completedHandlerIsNotCancelledWhileAcknowledging() throws Exception {
var acknowledging = new CountDownLatch(1);
var release = new CountDownLatch(1);
@@ -324,6 +329,7 @@ public void afterAttempt(
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void jobTimeoutDoesNotDependOnTheDispatcher() throws Exception {
var blocked = new CountDownLatch(1);
var release = new CountDownLatch(1);
@@ -405,6 +411,7 @@ void oversizedDurationsFailDuringConfiguration(String option) {
@ParameterizedTest
@ValueSource(strings = {"error", "shutdown", "snooze"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void firstStepCursorSurvivesIncompleteAttempt(String outcome) throws Exception {
var client = client();
var entered = new CountDownLatch(1);
@@ -442,6 +449,7 @@ void firstStepCursorSurvivesIncompleteAttempt(String outcome) throws Exception {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void oversizedSnoozeFailsTheAttemptInsteadOfStrandingIt() throws Exception {
var client = client();
var failed = new CompletableFuture();
@@ -517,6 +525,7 @@ void rescueCannotPreemptAConfiguredTimeout() {
@ParameterizedTest
@ValueSource(ints = {-1, 0, 120})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void rescueDefaultAccountsForTheJobTimeout(int timeoutMinutes) throws Exception {
var rescue = new CompletableFuture();
var client =
@@ -540,6 +549,7 @@ public boolean rescue(Client client, Rescue request) {
}
@Test
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void goQueueNotificationsRespectTopicsAndSurviveMalformedPayloads() throws Exception {
var client = client();
var ready = new CountDownLatch(1);
@@ -682,6 +692,7 @@ private static tools.jackson.databind.JsonNode notification(String name) throws
@ParameterizedTest
@ValueSource(strings = {"observer", "subscriber", "errorHandler"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void callbackFailuresDoNotLoseWorkerSlots(String callback) throws Exception {
var client = client();
var completed = new LinkedBlockingQueue();
@@ -738,6 +749,7 @@ void callbackFailuresDoNotLoseWorkerSlots(String callback) throws Exception {
"nanosecond_overflow",
"timestamp_overflow"
})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void invalidRetryPoliciesFallBack(String policy) throws Exception {
var client = client();
var failed = new LinkedBlockingQueue();
@@ -777,6 +789,7 @@ void invalidRetryPoliciesFallBack(String policy) throws Exception {
@ParameterizedTest
@CsvSource({"false,1,5000", "true,1,5000", "false,3600,1", "true,3600,1"})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void shortDelaysWakeFetchingBeforeThePollInterval(
boolean snooze, long serviceSeconds, long maintenanceMillis) throws Exception {
var client = client();
@@ -823,6 +836,7 @@ void shortDelaysWakeFetchingBeforeThePollInterval(
@ParameterizedTest
@ValueSource(booleans = {false, true})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void shutdownRespectsTheHandlersOutcome(boolean interrupted) throws Exception {
var client = client();
var entered = new CompletableFuture>();
@@ -864,6 +878,7 @@ void shutdownRespectsTheHandlersOutcome(boolean interrupted) throws Exception {
@ParameterizedTest
@ValueSource(booleans = {false, true})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void stoppingDuringAClaimPreservesCancellation(boolean cancel) throws Exception {
var claimed = new CountDownLatch(1);
var commit = new CountDownLatch(1);
@@ -932,6 +947,7 @@ public java.util.List claim(
@ParameterizedTest
@ValueSource(booleans = {false, true})
+ @SuppressWarnings("try") // Resources intentionally scope background activity.
void terminalFailuresDoNotConsultRetryPolicy(boolean cancel) throws Exception {
var client = client();
var failed = new LinkedBlockingQueue();