DanielLeens commented on PR #11545:
URL: https://github.com/apache/seatunnel/pull/11545#issuecomment-5394075927
# What Problem Does This PR Solve?
- User pain point: GitHub CI validated SeaTunnel almost exclusively on JDK
8/11 toolchains, so Java 17 module-system restrictions, internal-API removals,
and reflective-access changes stayed invisible until users hit them in
production. Separately, the shipped Docker image and `config/jvm_*_options`
never carried the `--add-opens`/`--add-exports` flags CI itself needs to pass
on newer JDKs.
- Fix approach: move the CI matrix from JDK 8/11 to JDK 11/17, raise the
Maven compiler baseline to Java 11 via `maven.compiler.release` (ten modules
pinned back to `release=8` where they must still emit Java 8 bytecode for older
dependencies), fix every JDK-17 incompatibility CI then surfaced, and carry the
runtime flags plus a JDK-11 Docker image into the actually-shipped product and
every E2E engine image.
- One-sentence summary: this is round 18 of review on an unusually deep,
well-converged PR; the two commits landed since the last full review fix the
sole remaining High-severity blocker (a self-caught compile error plus a
leftover JDK-8-matrix straggler), and I independently confirmed both fixes are
working against a live, still-in-progress CI run rather than trusting the diff
alone.
**Housekeeping note.** Sorry for the one gap in the last 17 rounds'
otherwise very thorough documentation sweep — this round's fresh full-diff pass
(not incremental) found `docs/{en,zh}/developer/shade-guide.md` still says
"Java 8+" as a prerequisite, contradicting the Java 11 baseline this PR itself
documents everywhere else. That's a genuine miss in a check ("does every doc
location agree on the new minimum") that prior rounds explicitly claimed to
have completed. See Issue 6.
# 1. Code Change Review
## 1.1 Core Logic Analysis
**The two commits since the last full review (2026-08-23T11:28Z),
independently read from the current head `51d884bfb`:**
1. `2cec73da1` (`[Fix][E2E] Use the inherited server field in PythonIT`) —
one-line fix: `PythonIT.installPythonIfNecessary()` called
`container.execInContainer(...)`, but `PythonIT extends SeaTunnelContainer`,
which has no field named `container` (the real field is `protected
GenericContainer<?> server`). This was a genuine compile break in the commit
the *previous* review round had endorsed by reading, not by a completed compile
— the fork's queued CI run for that head hadn't finished when that round was
written. Daniel self-caught this via a later completed CI run and posted a
self-correcting issue comment before this round started; this commit is exactly
that fix, and it is correct (`server.execInContainer(...)` matches the actual
inherited field).
2. `51d884bfb` (`[Fix][CI] Migrate google-pubsub-connector-it to the JDK
11/17 matrix`) — the `google-pubsub-connector-it` job in `backend.yml` had been
left on `java: [ '8', '11' ]` while every other job in the file was already
converted to `[ '11', '17' ]`. This commit converts it and adds `fail-fast:
false`, matching the file's established per-job convention. Independently
verified: `git show pr-11545:.github/workflows/backend.yml | grep -c "java: \[
'11', '17' \]"` and a search for any remaining `'8'` matrix entry both confirm
zero stragglers now — the whole file is internally consistent.
**Independent full-diff re-sweep this round (not incremental), focused on
the areas the task brief called out:**
- **CI workflow consistency** — read every `.github/workflows/*.yml` file's
Java references in full, not just the diff hunks. `backend.yml`,
`benchmarks.yml`, `codeql.yaml`, `publish-docker.yaml`,
`upgrade_compatibility.yml` are all uniformly on `11`/`17`. `build_main.yml`,
`schedule_backend.yml`, `publish-e2e-spark-images.yaml`,
`notify_test_workflow.yml`, `update_build_status.yml` have no Java version
references at all (orchestration-only), so they correctly need no change. No
stale JDK 8 matrix entry survives anywhere in `.github/workflows/`.
- **Downstream-compatibility for older Flink/Spark consumers** — correctly
and explicitly documented in `incompatible-changes.md`: "Third-party connectors
that are themselves compiled for Java 8 keep working. A Java 11 JVM loads older
class files without changes, so only the JVM version matters." The ten
`release=8`-pinned modules (`connector-cdc-tidb-e2e`, `connector-fluss-e2e`,
`connector-tdengine-e2e`, `connector-typesense-e2e`, `seatunnel-flink-examples`
+ its 3 sub-modules, `seatunnel-format-protobuf`, `seatunnel-ci-tools`) all
already carried explicit `<source>8</source>`/`<target>8</target>` **before**
this PR (verified via the diff hunks — only the `<release>8</release>` line is
new in each), so this PR is faithfully carrying forward pre-existing,
intentional pins under the new `release`-based mechanism, not inventing new
ones. No shipped production connector module is left targeting Java 8 bytecode;
only test/example modules with known old-dependency constraints are p
inned.
- **`connector-fluss`'s new `commons-lang3` pin + relocation** — traced the
actual bug: `fluss-client` calls `SystemUtils.isJavaVersionAtLeast`, which NPEs
on `JavaVersion.get(...)` returning `null` for JDK 11+ against an old
`commons-lang3`. The real-world trigger named in the code comment is Spark 2.4
putting its own old `commons-lang3` (3.5) on the classpath ahead of whatever
this module bundles — that's why relocation (not just a version bump) is
necessary: it guarantees `fluss-client`'s call resolves against the connector's
own bundled (and patched-in-place) copy regardless of classloader ordering.
`${commons-lang3.version}` resolves to `3.18.0` (well past the
`JavaVersion.JAVA_17` constant's introduction), so the fix is durable, not just
past-JDK-11-only. The new `<build>` shade block with no `<artifactSet>`
restriction matches the established pattern used by sibling connectors (e.g.
`connector-google-pubsub`'s shade config), so it's not a deviation from
convention — t
hough see Issue 7 for one small gap relative to that same sibling pattern.
Runtime path this PR changes (build/CI/deploy plane only; no job-execution
data path is touched):
```text
GitHub Actions matrix (backend.yml, CodeQL, publish-docker,
upgrade-compatibility, benchmarks.yml)
-> JDK 11 / JDK 17 toolchains (was 8 / 11), now with zero stale JDK-8
stragglers (this round's fix)
-> mvnw compile with maven.compiler.release=11 (10 modules pinned to
release=8, pre-existing pins carried forward)
-> seatunnel-dist/src/main/docker/Dockerfile: eclipse-temurin:11-jdk +
apt-get install python3
-> config/jvm_{master,worker,client}_options, jvm_options: carry
--add-opens/--add-exports
-> (separately) SeaTunnelContainer.JDK_DOCKER_IMAGE =
eclipse-temurin:11-jdk,
python3 installed at test runtime via installPythonIfNecessary() (now
compiles; confirmed green — see 1.4)
```
## 1.2 Compatibility Impact
**Partially incompatible, correctly documented.** Raising the minimum Java
runtime from 8 to 11 is a breaking change for any deployment still running the
SeaTunnel process (or a Flink/Spark cluster it submits to) on Java 8, captured
in both `docs/en` and `docs/zh` `introduction/concepts/incompatible-changes.md`
with impact and a migration guide. No SeaTunnel config `Option`, public API,
job-file format, or checkpoint/savepoint format is touched. The one gap found
this round is a stale prerequisite statement in a developer-facing doc (Issue
6), not a functional compatibility gap.
## 1.3 Performance / Side-Effect Analysis
No hot-path/runtime performance impact; this is build, CI, and deployment
tooling only. The one previously-identified side effect — `PythonIT`'s
`installPythonIfNecessary()` doing a live `apt-get install` inside the test
container at `@BeforeAll` time, a new network dependency the old pre-baked base
image didn't have — is unchanged by this round's fix and remains worth watching
for CI flakiness, though it isn't new since the last review.
## 1.4 Error Handling and Logging — Live CI Verification and Issue List
I did not stop at reading the diff. I pulled the current state of the fork's
live Actions run for this exact head (`DanielLeens/seatunnel` run
`32697371689`, still `in_progress` at review time) to confirm the two delta
commits actually work, not just read correctly:
- `google-pubsub-connector-it (11, ubuntu-latest)` and `(17,
ubuntu-latest)`: both **success** — confirms the matrix-migration fix (commit
2) is not just syntactically consistent but functionally correct.
- `all-connectors-it-5 (11, ubuntu-latest)` (the bucket containing
`PythonIT`): **success** — confirms the `server` field fix (commit 1) compiles
and the Python E2E test passes end-to-end on JDK 11 with the new
install-at-runtime `python3` step.
- `all-connectors-it-5 (17, ubuntu-latest)`: still `in_progress` at review
time — not yet confirmed, but there is no structural reason to expect
JDK-17-specific divergence given the JDK-11 lane is clean and both
`google-pubsub` lanes (11 and 17) already match.
- `all-connectors-it-1 (17, ubuntu-latest)`: **failure**, isolated to
`connector-couchbase-e2e`. Pulled the job log directly — this is the
previously-tracked `CouchbaseIT` container-bootstrap flake (independently fixed
by PR #11845, unrelated to this PR's JDK changes). Matches Issue 2's carryover
status exactly.
- `rocketmq-connector-it (11, ubuntu-latest)`: **failure**, new observation
this round. Pulled the job log: `RocketMqIT.testSourceRocketMqRestore` failed
with `AssertionFailedError: Unexpected sink message count after restore.
Expected: 45, actual: 46` after a 53-minute run through the full 87-test suite.
This is an off-by-one message-count assertion in a checkpoint-restore test —
the classic signature of an at-least-once redelivery timing flake, not a
JDK-bytecode or module-system issue. Nothing in this PR's diff touches
`connector-rocketmq` or its E2E test. See Issue 8.
- `kudu-connector-it (11 and 17, ubuntu-latest)`: both `cancelled` —
fail-fast fallout from the Couchbase/RocketMQ failures elsewhere in the same
run, not independent findings.
**Formal issue list** (carryover items re-verified directly against current
source this round, not assumed unchanged; new items marked accordingly):
**Issue 1 (Medium, downgraded from High — code-level fix confirmed working,
CI still finishing) — Docker/E2E `python3` gap fix now live-verified**
- Location: `seatunnel-dist/src/main/docker/Dockerfile:15-17`;
`seatunnel-e2e/.../PythonIT.java`.
- Problem: was the sole confirmed blocker from the last full round. Both the
shipped-image fix and the E2E-harness fix are now committed.
- Potential risk: the JDK 17 lane of `all-connectors-it-5` had not finished
at review time, so full confirmation across both JDKs is still pending, though
the JDK 11 lane and both `google-pubsub` lanes are already green with no sign
of JDK-version-specific divergence.
- Best improvement: none needed if the JDK 17 lane finishes green, which is
expected.
- Severity: Medium (verification gap, not a known code defect). Raised by
another reviewer: Yes (@SEZ9), carryover, now materially advanced by this
round's live CI check.
**Issue 2 (Low, carryover, re-confirmed today) — `CouchbaseIT` failure on
the JDK 17 lane, unrelated to this PR**
- Location: `all-connectors-it-1 (17, ubuntu-latest)` (bucket assignment
shifts run to run; same underlying flake).
- Problem: confirmed again this round via a fresh log pull — same
container-bootstrap-timeout signature tracked by PR #11845, independent of this
PR's Dockerfile/JDK changes.
- Severity: Low. Raised by another reviewer: Yes (@SEZ9).
**Issue 3 (Medium, carryover, still open) — `upgrade_compatibility.yml` runs
on JDK 17 against released `2.3.13` artifacts with no independent confirmation
yet that the upgrade path itself works on the new baseline**
- Location: `.github/workflows/upgrade_compatibility.yml`.
- Severity: Medium. Raised by another reviewer: No.
**Issue 4 (Medium, carryover, still open) — No Maven Enforcer
`requireJavaVersion` rule for a contributor still on JDK 8**
- Location: root `pom.xml` (absent). Re-verified: still no
`maven-enforcer-plugin` `requireJavaVersion` rule in the current `pom.xml`.
- Severity: Medium, non-blocking quality-of-life. Raised by another
reviewer: No.
**Issue 5 (Medium, carryover, still open) — Kudu/Paimon Kerberos reflection
shims diverge in failure semantics**
- Location: `KuduUtil.java:140-160` vs `PaimonSecurityContext.java:139-160`.
- Problem: both replace the now-non-compiling `sun.security.krb5.Config`
import with `Class.forName(...).getMethod("refresh").invoke(null)`, correctly
(verified: `refresh()` is public static, so `--add-exports` alone is sufficient
and the JDK-17-vs-11 relaxed-encapsulation difference does matter here —
re-verified this is a genuine requirement, not defensive). But `KuduUtil`'s
helper swallows `ReflectiveOperationException | RuntimeException` internally
and moves `KerberosName.resetDefaultRealm()` outside the try, so it now runs
unconditionally even after a failed refresh — a real behavior change from the
pre-PR code (which skipped `resetDefaultRealm()` on failure) and from
`PaimonSecurityContext`'s otherwise-identical fix in this same PR (which
correctly preserves the skip-on-failure ordering). Neither shim unwraps
`InvocationTargetException`, so a genuine `KrbException` from a malformed
`krb5.conf` is logged as a generic reflection failure.
- Best improvement: make `KuduUtil` match `PaimonSecurityContext`'s ordering
(propagate, skip `resetDefaultRealm()` on failure), or state explicitly that
the divergence is deliberate; unwrap `InvocationTargetException` in both.
- Severity: Medium, non-blocking (Hadoop's `resetDefaultRealm()` is itself
internally exception-safe in practice, so the real-world blast radius is small,
but it is an unflagged semantic change touching Kerberos-secured cluster
behavior). Raised by another reviewer: No (this is Daniel's own carryover
finding from prior rounds, re-verified unchanged against current source this
round).
**Issue 6 (Low, NEW this round) — `docs/{en,zh}/developer/shade-guide.md`
still lists "Java 8+" as a prerequisite**
- Location: `docs/en/developer/shade-guide.md:88`;
`docs/zh/developer/shade-guide.md:88`.
- Problem: unlike `docs/{en,zh}/developer/setup.md`, which this PR correctly
updated to "JDK11/JDK17 are supported by now", `shade-guide.md`'s "Java 8+"
prerequisite line was not touched. It isn't strictly false in isolation ("8+"
technically includes 11/17), but it directly contradicts this same PR's own
`incompatible-changes.md` entry stating the minimum is now Java 11, and could
lead a contributor to set up a Java 8 toolchain that then fails to build
(`maven.compiler.release=11` cannot be satisfied by a JDK 8 `javac`).
- Potential risk: low — following the stale doc produces an immediate, clear
Maven build error rather than a silent misbehavior, so this is a
documentation-quality gap rather than a functional risk.
- Best improvement: change both files' "Java 8+" line to match `setup.md`'s
wording.
- Severity: Low. Raised by another reviewer: No — this is a genuine gap in
this round's own full sweep of every doc location; the prior 17 rounds'
documentation checks did not catch it.
**Issue 7 (Low, NEW this round) — `connector-fluss`'s new shade block omits
the `META-INF/*.SF|.DSA|.RSA` filter its sibling connectors use**
- Location: `seatunnel-connectors-v2/connector-fluss/pom.xml` (new `<build>`
block).
- Problem: `connector-google-pubsub/pom.xml` (and others) include a
`<filters><filter><artifact>*:*</artifact><excludes>` block dropping signature
files to avoid "Invalid signature file digest" errors when shading signed jars
into an uber jar. `connector-fluss`'s otherwise-identical new shade block lacks
it.
- Potential risk: low unless one of `fluss-client`'s transitive dependencies
turns out to be signed; not proven to be a live problem, just a gap versus this
codebase's own established defensive pattern for the same plugin usage.
- Best improvement: add the same filter block for consistency, at the
author's discretion.
- Severity: Low. Raised by another reviewer: No.
**Issue 8 (Low, NEW this round) — `RocketMqIT.testSourceRocketMqRestore`
failed on the live CI run, likely a pre-existing flake unrelated to this PR**
- Location: `rocketmq-connector-it (11, ubuntu-latest)`, run `32697371689`.
- Problem: `AssertionFailedError: Unexpected sink message count after
restore. Expected: 45, actual: 46` — an off-by-one message-count mismatch in a
checkpoint-restore assertion, the standard signature of an at-least-once
redelivery timing race. Nothing in this PR touches `connector-rocketmq` or its
E2E test.
- Best improvement: re-run to confirm it's non-deterministic and unrelated
to this PR; if it reproduces consistently on this exact head, escalate
separately.
- Severity: Low, not believed to be PR-caused. Raised by another reviewer:
No.
## 2. Code Quality Assessment
### 2.1 Coding Standards
Primarily CI/build-configuration, Dockerfile, and reflection-shim changes.
The new `installPythonIfNecessary()` and `EngineImageJdkUpgrader` carry
explanatory Javadoc. No new core method or non-trivial field lacks an
explanation. `KuduUtil.refreshJdkKerberosConfig()`'s Javadoc correctly explains
why reflection is needed; it does not currently mention the ordering change
flagged in Issue 5.
### 2.2 Test Coverage and Test Stability
**Stability rating: Risk present.** Not because of a flaky pattern in this
PR's own new test code, but because: (a) the JDK 17 lane of the Python E2E fix
is still finishing at review time, (b) the live `apt-get`-at-test-time step in
`PythonIT` is a genuinely new potential source of setup flakiness versus the
old pre-baked image (pre-existing observation, unchanged this round), and (c)
`RocketMqIT`'s restore-count flake (Issue 8) surfaced on this exact run,
independent of this PR.
`ServerExecuteCommandTest.testSupportedJavaVersionCheck()` correctly asserts
the new `isUnsupportedJavaVersion()` on its only reachable (`false`) branch —
the `true` branch is structurally dead code post-this-PR (already a
well-documented carryover finding across prior rounds, unchanged and
non-blocking).
### 2.3 Documentation Updates
`docs/{en,zh}/introduction/concepts/incompatible-changes.md`, `docker.md`,
`kubernetes.mdx`, and `developer/setup.md` are all consistent with the Java 11
baseline and the `11-jdk` image. `docs/{en,zh}/developer/shade-guide.md` is the
one location this round found still stale (Issue 6).
# 3. Architectural Soundness
## 3.1 Elegance of the Solution
Using `maven.compiler.release` instead of relying on `-source`/`-target`
alone remains the correct fix for its target problem (constraining the API
surface, not just the bytecode level), and pinning only the ten modules that
must stay on Java 8 bytecode — all pre-existing pins carried forward, not new
ones invented — is precise and minimal. The two-part `python3` fix (shipped
Dockerfile + independent E2E-harness base image) correctly addresses two
genuinely separate code paths that share a root cause but no build step, as
traced in the prior round and re-confirmed here.
## 3.2 Maintainability
The CI matrix replacement (8/11 → 11/17, not additive) keeps CI leg count
unchanged, and this round's fix closes the last stale-matrix straggler, so the
whole workflow file is now internally uniform — a real maintainability win,
since a future contributor scanning `backend.yml` will no longer find one job
silently still exercising an unrelated toolchain pair.
## 3.3 Extensibility
The `EngineImageJdkUpgrader` derived-build pattern for Flink/Spark E2E
images remains a reasonable, reusable approach for future JDK bumps of those
specific images. `SeaTunnelContainer`'s direct-pull-and-copy-binaries pattern,
by contrast, has no equivalent build-time hook, so any future missing-tool gap
in that image will again require a runtime `execInContainer` install step (as
this PR's own fix demonstrates) rather than a Dockerfile change — worth keeping
in mind for the next base-image swap.
## 3.4 Historical-Version Compatibility
No SeaTunnel job-file, config `Option`, checkpoint, or savepoint format is
touched by this PR. The compatibility surface is entirely "what JVM/toolchain
does the SeaTunnel process itself, and the Docker image that ships it,
require," and that surface is correctly and thoroughly documented as an
incompatible change, with the one stale-doc exception in Issue 6.
# 4. Issue Summary
| # | Issue | Location | Severity |
|---|-------|----------|----------|
| 1 | `python3` fix now live-verified on JDK 11 and both `google-pubsub`
lanes; JDK 17 Python lane still finishing | Dockerfile:15-17; PythonIT.java |
Medium |
| 2 | `CouchbaseIT` failure on 17/ubuntu lane, re-confirmed unrelated to
this PR | all-connectors-it-1 (17, ubuntu-latest) | Low |
| 3 | `upgrade_compatibility.yml`'s JDK-17 run not yet independently
confirmed green | .github/workflows/upgrade_compatibility.yml | Medium |
| 4 | No Maven Enforcer `requireJavaVersion` rule for JDK 8 contributors |
pom.xml | Medium |
| 5 | Kudu/Paimon Kerberos shims diverge in failure ordering
(`resetDefaultRealm` now unconditional in Kudu only) | KuduUtil.java:140-160;
PaimonSecurityContext.java:139-160 | Medium |
| 6 | `shade-guide.md` (en+zh) still says "Java 8+", contradicting the new
Java 11 baseline | docs/{en,zh}/developer/shade-guide.md:88 | Low |
| 7 | `connector-fluss`'s new shade block omits the signature-file filter
its sibling connectors use | connector-fluss/pom.xml | Low |
| 8 | `RocketMqIT.testSourceRocketMqRestore` failed on this run — likely
unrelated pre-existing flake | rocketmq-connector-it (11, ubuntu-latest) | Low |
# 5. Merge Recommendation
### Conclusion: Ready to merge after fixes
**1. Blockers — must be fixed / confirmed**
1. Issue 1 — obtain a completed, green run of the JDK 17
`all-connectors-it-5` lane (Python E2E) for this head or a subsequent one. The
JDK 11 lane and both `google-pubsub` lanes are already confirmed green with the
same fix, so this is a verification step rather than an expected code problem.
2. Triage Issues 2 and 8 (Couchbase, RocketMQ) as the pre-existing/unrelated
flakes the evidence points to — re-run and confirm neither reproduces
deterministically against this exact head before treating the run as clean.
**2. Recommended fixes — non-blocking**
1. Issue 3 — get at least one confirmed-green run of
`upgrade_compatibility.yml` on the new matrix.
2. Issue 4 — add a Maven Enforcer `requireJavaVersion` rule.
3. Issue 5 — align `KuduUtil`'s Kerberos-refresh failure ordering with
`PaimonSecurityContext`'s (or document the divergence as deliberate), and
unwrap `InvocationTargetException` in both.
4. Issue 6 — update `shade-guide.md` (en+zh) to state the Java 11 baseline.
5. Issue 7 — add the signature-file shade filter to `connector-fluss` for
consistency with sibling connectors.
**Overall assessment.** This PR continues to do exactly what a
JDK-baseline-raise PR should: move CI forward first, fix each incompatibility
narrowly, and close the loop into the shipped Docker image, JVM option files,
and every E2E engine image. This round's two commits close the last confirmed
code-level gap (a self-caught compile error and a leftover JDK-8 CI straggler),
and — unlike the prior round, which could only read the fix and wait on a stuck
`queued` run — I pulled the live, in-progress fork run directly and confirmed
both fixes are actually working (JDK 11 Python lane green, both `google-pubsub`
lanes green), not just plausible on paper. The two live failures on this run
(Couchbase, RocketMQ) both carry signatures pointing away from this PR rather
than toward it. The remaining open items are all Medium-or-lower, non-blocking
quality/consistency gaps accumulated and correctly tracked across 17 prior
rounds, plus two new small findings from this round's own fresh ful
l-diff and full-doc sweep (Issues 6 and 7). As the PR author is also the
account posting this review, this is not an independent approval — a
write-capable maintainer must still perform the final review, and should wait
for the JDK 17 Python lane and a clean re-run of the two flake candidates
before merging.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]