This is an automated email from the ASF dual-hosted git repository.
Abacn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git
The following commit(s) were added to refs/heads/master by this push:
new bd102581f7f Run portable ValidatesRunner tests one at a time (#40632)
bd102581f7f is described below
commit bd102581f7f8fd9f446a22ff490cf272be9f4077
Author: Abdelrahman Ibrahim <[email protected]>
AuthorDate: Mon Oct 19 18:29:50 2026 +0300
Run portable ValidatesRunner tests one at a time (#40632)
* run portable ValidatesRunner tests one at a time
* delay flink teardown
---
.../beam_PostCommit_Java_PVR_Flink_Batch.json | 2 +-
.../beam_PostCommit_Java_PVR_Flink_Streaming.json | 2 +-
.../FlinkExecutableStageContextFactory.java | 51 ++++++++++++++++------
runners/flink/job-server/flink_job_server.gradle | 2 +
.../FlinkExecutableStageContextFactory.java | 51 ++++++++++++++++------
5 files changed, 78 insertions(+), 30 deletions(-)
diff --git a/.github/trigger_files/beam_PostCommit_Java_PVR_Flink_Batch.json
b/.github/trigger_files/beam_PostCommit_Java_PVR_Flink_Batch.json
index 6f486a1f8c1..73e12ca8961 100644
--- a/.github/trigger_files/beam_PostCommit_Java_PVR_Flink_Batch.json
+++ b/.github/trigger_files/beam_PostCommit_Java_PVR_Flink_Batch.json
@@ -1,6 +1,6 @@
{
"comment": "Modify this file in a trivial way to cause this test suite to
run",
"https://github.com/apache/beam/pull/32440": "test new datastream runner for
batch",
- "modification": 2,
+ "modification": 8,
"https://github.com/apache/beam/pull/39990": "removing dead code from
FnApiDoFnRunner"
}
diff --git
a/.github/trigger_files/beam_PostCommit_Java_PVR_Flink_Streaming.json
b/.github/trigger_files/beam_PostCommit_Java_PVR_Flink_Streaming.json
index 626e4fea5c8..ebd00405531 100644
--- a/.github/trigger_files/beam_PostCommit_Java_PVR_Flink_Streaming.json
+++ b/.github/trigger_files/beam_PostCommit_Java_PVR_Flink_Streaming.json
@@ -1,6 +1,6 @@
{
"comment": "Modify this file in a trivial way to cause this test suite to
run",
- "modification": 2,
+ "modification": 3,
"https://github.com/apache/beam/pull/32440": "test new datastream runner for
batch",
"https://github.com/apache/beam/pull/39990": "removing dead code from
FnApiDoFnRunner"
}
diff --git
a/runners/flink/2.0/src/main/java/org/apache/beam/runners/flink/translation/functions/FlinkExecutableStageContextFactory.java
b/runners/flink/2.0/src/main/java/org/apache/beam/runners/flink/translation/functions/FlinkExecutableStageContextFactory.java
index 3f42eb93e4e..afcfb9d6730 100644
---
a/runners/flink/2.0/src/main/java/org/apache/beam/runners/flink/translation/functions/FlinkExecutableStageContextFactory.java
+++
b/runners/flink/2.0/src/main/java/org/apache/beam/runners/flink/translation/functions/FlinkExecutableStageContextFactory.java
@@ -22,7 +22,9 @@ import java.util.concurrent.ConcurrentMap;
import
org.apache.beam.runners.fnexecution.control.DefaultExecutableStageContext;
import org.apache.beam.runners.fnexecution.control.ExecutableStageContext;
import
org.apache.beam.runners.fnexecution.control.ReferenceCountingExecutableStageContextFactory;
+import org.apache.beam.runners.fnexecution.control.StageBundleFactory;
import org.apache.beam.runners.fnexecution.provisioning.JobInfo;
+import org.apache.beam.sdk.util.construction.graph.ExecutableStage;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
/** Singleton class that contains one {@link ExecutableStageContext.Factory}
per job. */
@@ -30,10 +32,6 @@ public class FlinkExecutableStageContextFactory implements
ExecutableStageContex
private static final FlinkExecutableStageContextFactory instance =
new FlinkExecutableStageContextFactory();
- // This map should only ever have a single element, as each job will have
its own
- // classloader and therefore its own instance of
FlinkExecutableStageContextFactory. This
- // code supports multiple JobInfos in order to provide a sensible
implementation of
- // Factory.get(JobInfo), which in theory could be called with different
JobInfos.
private static final ConcurrentMap<String, ExecutableStageContext.Factory>
jobFactories =
new ConcurrentHashMap<>();
@@ -48,16 +46,41 @@ public class FlinkExecutableStageContextFactory implements
ExecutableStageContex
ExecutableStageContext.Factory jobFactory =
jobFactories.computeIfAbsent(
jobInfo.jobId(),
- k -> {
- return ReferenceCountingExecutableStageContextFactory.create(
- DefaultExecutableStageContext::create,
- // Clean up context immediately if its class is not loaded
on Flink parent
- // classloader.
- (caller) ->
- caller.getClass().getClassLoader()
- !=
StreamExecutionEnvironment.class.getClassLoader());
- });
-
+ k ->
+ ReferenceCountingExecutableStageContextFactory.create(
+ info -> new JobScopedExecutableStageContext(info, k),
+ // Release immediately when the factory is not on the
Flink parent classloader
+ // (so cleanup still works after that classloader is
discarded). Otherwise keep
+ // the default environment cache delay so DoFn @Teardown
can finish first.
+ caller ->
+ caller.getClass().getClassLoader()
+ !=
StreamExecutionEnvironment.class.getClassLoader()));
return jobFactory.get(jobInfo);
}
+
+ private static class JobScopedExecutableStageContext implements
ExecutableStageContext {
+ private final DefaultExecutableStageContext delegate;
+ private final String jobId;
+
+ private JobScopedExecutableStageContext(JobInfo jobInfo, String jobId) {
+ this.delegate = DefaultExecutableStageContext.create(jobInfo);
+ this.jobId = jobId;
+ }
+
+ @Override
+ public StageBundleFactory getStageBundleFactory(ExecutableStage
executableStage) {
+ return delegate.getStageBundleFactory(executableStage);
+ }
+
+ @Override
+ public void close() throws Exception {
+ try {
+ delegate.close();
+ } finally {
+ // Drop the per-job factory entry so a long-lived JVM that runs many
jobs does not
+ // accumulate one entry per finished job.
+ jobFactories.remove(jobId);
+ }
+ }
+ }
}
diff --git a/runners/flink/job-server/flink_job_server.gradle
b/runners/flink/job-server/flink_job_server.gradle
index 6f39b67abf7..edf55807503 100644
--- a/runners/flink/job-server/flink_job_server.gradle
+++ b/runners/flink/job-server/flink_job_server.gradle
@@ -129,6 +129,7 @@ runShadow {
jvmArgs +=
["-Dorg.slf4j.simpleLogger.defaultLogLevel=${project.property('logLevel')}"]
}
+
def portableValidatesRunnerTask(String name, String mode, boolean
checkpointing, boolean docker) {
def pipelineOptions = [
// Limit resource consumption via parallelism
@@ -257,6 +258,7 @@ def flinkJobServerJvmArgs() {
[validatesPortableRunnerDocker, validatesPortableRunnerBatchDataSet,
validatesPortableRunnerBatch, validatesPortableRunnerStreaming,
validatesPortableRunnerStreamingCheckpoint].each { task ->
task.configure {
jvmArgs += flinkJobServerJvmArgs()
+ systemProperty "beam.validatesRunner.parallelThreads", "1"
}
}
diff --git
a/runners/flink/src/main/java/org/apache/beam/runners/flink/translation/functions/FlinkExecutableStageContextFactory.java
b/runners/flink/src/main/java/org/apache/beam/runners/flink/translation/functions/FlinkExecutableStageContextFactory.java
index a2e3bb3142b..5a11336add1 100644
---
a/runners/flink/src/main/java/org/apache/beam/runners/flink/translation/functions/FlinkExecutableStageContextFactory.java
+++
b/runners/flink/src/main/java/org/apache/beam/runners/flink/translation/functions/FlinkExecutableStageContextFactory.java
@@ -22,7 +22,9 @@ import java.util.concurrent.ConcurrentMap;
import
org.apache.beam.runners.fnexecution.control.DefaultExecutableStageContext;
import org.apache.beam.runners.fnexecution.control.ExecutableStageContext;
import
org.apache.beam.runners.fnexecution.control.ReferenceCountingExecutableStageContextFactory;
+import org.apache.beam.runners.fnexecution.control.StageBundleFactory;
import org.apache.beam.runners.fnexecution.provisioning.JobInfo;
+import org.apache.beam.sdk.util.construction.graph.ExecutableStage;
import org.apache.flink.api.java.ExecutionEnvironment;
/** Singleton class that contains one {@link ExecutableStageContext.Factory}
per job. */
@@ -30,10 +32,6 @@ public class FlinkExecutableStageContextFactory implements
ExecutableStageContex
private static final FlinkExecutableStageContextFactory instance =
new FlinkExecutableStageContextFactory();
- // This map should only ever have a single element, as each job will have
its own
- // classloader and therefore its own instance of
FlinkExecutableStageContextFactory. This
- // code supports multiple JobInfos in order to provide a sensible
implementation of
- // Factory.get(JobInfo), which in theory could be called with different
JobInfos.
private static final ConcurrentMap<String, ExecutableStageContext.Factory>
jobFactories =
new ConcurrentHashMap<>();
@@ -48,16 +46,41 @@ public class FlinkExecutableStageContextFactory implements
ExecutableStageContex
ExecutableStageContext.Factory jobFactory =
jobFactories.computeIfAbsent(
jobInfo.jobId(),
- k -> {
- return ReferenceCountingExecutableStageContextFactory.create(
- DefaultExecutableStageContext::create,
- // Clean up context immediately if its class is not loaded
on Flink parent
- // classloader.
- (caller) ->
- caller.getClass().getClassLoader()
- != ExecutionEnvironment.class.getClassLoader());
- });
-
+ k ->
+ ReferenceCountingExecutableStageContextFactory.create(
+ info -> new JobScopedExecutableStageContext(info, k),
+ // Release immediately when the factory is not on the
Flink parent classloader
+ // (so cleanup still works after that classloader is
discarded). Otherwise keep
+ // the default environment cache delay so DoFn @Teardown
can finish first.
+ caller ->
+ caller.getClass().getClassLoader()
+ != ExecutionEnvironment.class.getClassLoader()));
return jobFactory.get(jobInfo);
}
+
+ private static class JobScopedExecutableStageContext implements
ExecutableStageContext {
+ private final DefaultExecutableStageContext delegate;
+ private final String jobId;
+
+ private JobScopedExecutableStageContext(JobInfo jobInfo, String jobId) {
+ this.delegate = DefaultExecutableStageContext.create(jobInfo);
+ this.jobId = jobId;
+ }
+
+ @Override
+ public StageBundleFactory getStageBundleFactory(ExecutableStage
executableStage) {
+ return delegate.getStageBundleFactory(executableStage);
+ }
+
+ @Override
+ public void close() throws Exception {
+ try {
+ delegate.close();
+ } finally {
+ // Drop the per-job factory entry so a long-lived JVM that runs many
jobs does not
+ // accumulate one entry per finished job.
+ jobFactories.remove(jobId);
+ }
+ }
+ }
}