This is an automated email from the ASF dual-hosted git repository.
MartijnVisser pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git
The following commit(s) were added to refs/heads/master by this push:
new 4902753429f [FLINK-35562][table-planner] Bound result wait in
RestoreTestBase to avoid CI hangs (#28404)
4902753429f is described below
commit 4902753429fcca8975de66843bb3eab2b0e5a0de
Author: Martijn Visser <[email protected]>
AuthorDate: Thu Jun 18 06:56:47 2026 -0700
[FLINK-35562][table-planner] Bound result wait in RestoreTestBase to avoid
CI hangs (#28404)
* [FLINK-35562][table-planner] Bound result wait in RestoreTestBase to
avoid CI hangs
testRestore waits on an unbounded future that never completes when a
PROCTIME() window splits records differently than when the expected data
was captured, hanging the surefire fork until the CI watchdog kills it.
Bound the wait at 5 minutes and fail with the program id and the actual
sink results. Only the two proc-time restore tests (FLINK-35562,
FLINK-34404) use the affected INFINITE path; the proc-time nondeterminism
itself is left as follow-up.
Generated-by: Claude Opus 4.8 (1M context)
---
.../plan/nodes/exec/testutils/RestoreTestBase.java | 52 ++++++++++++++++++++--
1 file changed, 49 insertions(+), 3 deletions(-)
diff --git
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/nodes/exec/testutils/RestoreTestBase.java
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/nodes/exec/testutils/RestoreTestBase.java
index d64ac4f858e..f1cdc2ca0bc 100644
---
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/nodes/exec/testutils/RestoreTestBase.java
+++
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/nodes/exec/testutils/RestoreTestBase.java
@@ -76,6 +76,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
@@ -106,6 +108,10 @@ public abstract class RestoreTestBase implements
TableTestProgramRunner {
// This version can be set to generate savepoints for a particular Flink
version.
// By default, the savepoint is generated for the current version in the
default directory.
private static final FlinkVersion FLINK_VERSION = null;
+
+ // Bounds the wait for the expected sink results so a stuck job (e.g. an
unlucky
+ // processing-time window split) fails the test instead of hanging the
fork.
+ private static final long RESULT_AWAIT_TIMEOUT_MILLIS =
TimeUnit.MINUTES.toMillis(5);
private final Class<? extends ExecNode<?>> execNodeUnderTest;
private final List<Class<? extends ExecNode<?>>> childExecNodesUnderTest;
private final AfterRestoreSource afterRestoreSource;
@@ -276,6 +282,43 @@ public abstract class RestoreTestBase implements
TableTestProgramRunner {
});
}
+ private void awaitExpectedResults(
+ final TableTestProgram program,
+ final List<CompletableFuture<?>> futures,
+ final boolean ignoreAfter)
+ throws Exception {
+ try {
+ CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
+ .get(RESULT_AWAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ final StringBuilder message = new StringBuilder();
+ message.append("Sink did not produce the expected results within ")
+ .append(RESULT_AWAIT_TIMEOUT_MILLIS)
+ .append(" ms for program '")
+ .append(program.id)
+ .append("'.");
+ for (SinkTestStep sinkTestStep : program.getSetupSinkTestSteps()) {
+ // Mirror the expected set the observer waits on, so the dump
is exact.
+ final List<String> expected =
+ new
ArrayList<>(sinkTestStep.getExpectedBeforeRestoreAsStrings());
+ if (!ignoreAfter) {
+
expected.addAll(sinkTestStep.getExpectedAfterRestoreAsStrings());
+ }
+ message.append(System.lineSeparator())
+ .append("Sink '")
+ .append(sinkTestStep.name)
+ .append("' expected results: ")
+ .append(expected)
+ .append(System.lineSeparator())
+ .append("Sink '")
+ .append(sinkTestStep.name)
+ .append("' actual results: ")
+ .append(getActualResults(sinkTestStep,
sinkTestStep.name));
+ }
+ throw new AssertionError(message.toString(), e);
+ }
+ }
+
/**
* Execute this test to generate test files. Remember to be using the
correct branch when
* generating the test files.
@@ -336,7 +379,7 @@ public abstract class RestoreTestBase implements
TableTestProgramRunner {
compiledPlan.writeToFile(getPlanPath(program, getLatestMetadata()));
final TableResult tableResult = compiledPlan.execute();
- CompletableFuture.allOf(futures.toArray(new
CompletableFuture[0])).get();
+ awaitExpectedResults(program, futures, true);
final JobClient jobClient = tableResult.getJobClient().get();
final String savepoint =
jobClient
@@ -431,8 +474,11 @@ public abstract class RestoreTestBase implements
TableTestProgramRunner {
if (afterRestoreSource == AfterRestoreSource.INFINITE) {
final TableResult tableResult = compiledPlan.execute();
- CompletableFuture.allOf(futures.toArray(new
CompletableFuture[0])).get();
- tableResult.getJobClient().get().cancel().get();
+ try {
+ awaitExpectedResults(program, futures, false);
+ } finally {
+ tableResult.getJobClient().get().cancel().get();
+ }
} else {
compiledPlan.execute().await();
for (SinkTestStep sinkTestStep : program.getSetupSinkTestSteps()) {