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();