Skip to content

[DNM] chore(ci): build Hudi once per profile set and reuse it in the GitHub test jobs - #20363

Closed
databird07 wants to merge 1 commit into
apache:masterfrom
databird07:perf/ci-build-once
Closed

databird07 wants to merge 1 commit into
apache:masterfrom
databird07:perf/ci-build-once

Conversation

@databird07

Copy link
Copy Markdown
Contributor

Describe the issue this Pull Request addresses

Every test job in bot.yml runs its own mvn clean install -DskipTests before testing. In run 38362333401 the 11 builds that share a profile set took 63.5 of ~622 job-minutes.

Summary and Changelog

  • Three build jobs (JDK11/Spark 3.5, Java 17/Spark 4.2, Flink) save their module target/ directories and ~/.m2/.../org/apache/hudi as a workflow artifact (pax tar + zstd, duplicate jars hard-linked; ~1 GB).
  • Test jobs that use the same profiles restore that artifact instead of building. Restored timestamps are re-stamped (compress_mtimes.py) so Maven treats the outputs as up to date. Test steps themselves are unchanged.
  • Bundle validation, Spark 4 bundle validation and integration tests keep their own builds because they use different profiles.

Impact

CI-only. Projected saving is ~30 job-minutes per push. The critical path gets ~3 minutes longer, because test jobs wait for a build job. Locally, 20 runs each of in-job build vs. restored artifact gave identical test counts and identical JaCoCo coverage, with 0 recompiled sources after restore. This hasn't run on GitHub Actions yet, so this PR's own CI run is the first real check.

Risk Level

medium. Workflow restructuring that depends on the restored outputs being treated as up to date. Mitigated by manifest checks (commit and profile set) on restore and by the local comparison above. Reverting is a single-commit revert.

Documentation Update

none

Contributor's checklist

  • Read through contributor's guide
  • Enough context is provided in the sections above
  • Adequate tests were added if applicable

… test jobs

Every test job of bot.yml ran its own `mvn clean install -DskipTests` before its
test steps (about 95 of ~620 job-minutes of a master push). Jobs that build the
same profile set now restore one shared build instead.

What:
- build-jdk11-spark35 (scala-2.12, spark3.5, flink2.2, -Phudi-platform-service,
  -Pthrift-gen-source, in the hudi-ci docker image) serves
  test-spark-client-and-hadoop-common, test-utilities,
  test-common-and-other-modules and test-hudi-hadoop-mr-and-hudi-java-client.
- build-java17-spark42 (java17, scala-2.13, spark4.2) serves the five
  test-spark-java17-* jobs.
- build-flink (flink2.2 with avro 1.11.4 / parquet 1.15.2) serves test-flink-1/2.
- validate-bundles, validate-bundle-spark4 and integration-tests keep their own
  builds: they use other profiles (bundle deploy, -Pintegration-tests, other
  Spark/Flink versions), so their output is not the same build.

How:
- .github/actions/save-hudi-build packs every module target/ directory and
  ~/.m2/repository/org/apache/hudi (pax tar + zstd, identical target/lib jars
  hard-linked so they are stored once) and uploads them as a workflow artifact
  named hudi-build-<sha>-<jdk>-<profiles...>.
- .github/actions/restore-hudi-build downloads that artifact, checks that its
  manifest names this commit and this profile set, replaces the local
  org/apache/hudi repository with it, unpacks the target/ directories and
  re-stamps them (compress_mtimes.py) so Maven sees them as up to date: every
  distinct original millisecond keeps its order and gets its own millisecond
  just after the newest checked-out source, so neither javac, maven-jar-plugin
  nor scala-maven-plugin (which recompiles when a source is not older than its
  timestamp file) treats the restored outputs as stale.
- The test jobs drop their build step and restore instead; every test step
  (module lists, profiles, -Dtest / wildcardSuites filters, excludes) is
  unchanged. Docker based jobs mount the workspace at the same absolute path
  in the build and test containers, since Maven metadata stores absolute paths.

Review follow-ups: the save action chowns the packed target/ dirs and
org/apache/hudi to the runner user before hard-linking and packing (builds
in the hudi-ci container leave root-owned files), artifact retention is 7
days so "re-run failed jobs" keeps working for a week, and the three build
jobs get a 120-minute timeout instead of 60.


Measured locally (JDK 17, Maven 3.10.0, taskset -c 0-3, 20 runs each of
the "Java UT 1 - Common & Spark" step of test-spark-java17-java-tests-part1
narrowed to -Dtest=TestHoodieAvroUtils, JaCoCo on):
- in-job build (today):   20/20 exit 0, 103 tests, 0/0/0 fail/err/skip,
                          median 126.3 s, p90 127.6 s
- fresh checkout + restored artifact: 20/20 exit 0, 103 tests, 0/0/0,
                          0 recompiled sources, median 126.9 s, p90 128.0 s
- JaCoCo (hudi-common + hudi-spark): 1021 covered lines in every run of
  both series; intersection and union identical, no line lost or gained.
- Without the checkstyle cache refresh the restored runs took median
  143.4 s (checkstyle re-checked every source of the fresh checkout).
Artifact for the Java 17 / Spark 4.2 group: 1.07 GB (1.04 GB targets after
hard-linking duplicate target/lib jars, was 3.76 GB; 35 MB of
org/apache/hudi). Upstream run 38362333401 spent 63.5 of 621.8 job-minutes
in the 11 builds removed here; with three shared builds and the restores
the projected saving is about 30 job-minutes per push, while the critical
path gets about 3 minutes longer because test jobs wait for a build job.
@github-actions github-actions Bot added the size:L PR with lines of changes in (300, 1000] label Oct 16, 2026

@hudi-agent hudi-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ 🤖 This review was generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.

No reviewable code files in this PR.

cc @yihua

@databird07 databird07 changed the title chore(ci): build Hudi once per profile set and reuse it in the GitHub test jobs [DNM] chore(ci): build Hudi once per profile set and reuse it in the GitHub test jobs Oct 16, 2026
@databird07

Copy link
Copy Markdown
Contributor Author

Combined into #20364 so the total impact can be reviewed in one place; this commit is included there unchanged. Closing.

@databird07 databird07 closed this Oct 16, 2026
@codecov-commenter

codecov-commenter commented Oct 16, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.74%. Comparing base (e9da226) to head (fbd45ed).
⚠️ Report is 19 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master   #20363      +/-   ##
============================================
+ Coverage     80.70%   80.74%   +0.04%     
- Complexity    35124    35207      +83     
============================================
  Files          2553     2553              
  Lines        143524   143629     +105     
  Branches      17474    17623     +149     
============================================
+ Hits         115830   115975     +145     
+ Misses        19746    19694      -52     
- Partials       7948     7960      +12     
Components Coverage Δ
hudi-common 84.18% <ø> (+0.02%) ⬆️
hudi-client 83.96% <ø> (+0.01%) ⬆️
hudi-flink 86.08% <ø> (+0.02%) ⬆️
hudi-spark-datasource 74.19% <ø> (+<0.01%) ⬆️
hudi-utilities 78.15% <ø> (-0.02%) ⬇️
hudi-cli 70.80% <ø> (ø)
hudi-hadoop 71.18% <ø> (+0.02%) ⬆️
hudi-sync 76.85% <ø> (+0.26%) ⬆️
hudi-io 81.57% <ø> (+0.04%) ⬆️
hudi-timeline-service 83.41% <ø> (ø)
hudi-cloud 81.00% <ø> (ø)
hudi-kafka-connect 57.90% <ø> (+3.41%) ⬆️
Flag Coverage Δ
common-and-other-modules 52.64% <ø> (+0.11%) ⬆️
flink-integration-tests 49.65% <ø> (+0.06%) ⬆️
hadoop-mr-java-client 21.47% <ø> (-22.47%) ⬇️
integration-tests 13.45% <ø> (+<0.01%) ⬆️
spark-client-hadoop-common 32.69% <ø> (-5.99%) ⬇️
spark-java-tests 52.81% <ø> (+0.03%) ⬆️
spark-scala-tests 47.74% <ø> (-0.02%) ⬇️
utilities 30.29% <ø> (-6.59%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 47 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L PR with lines of changes in (300, 1000]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants