Speed up gtfs-rt integration tests: cache bundle builds + parallel forks#463
Conversation
The onebusaway-gtfsrt-integration-tests module dominated CI wall-clock (~13:51 of an ~18 min job), because AbstractGtfsRealtimeIntegrationTest's @before rebuilt the full GTFS transit-graph bundle before every test method, and the suite ran serially. - Build each dataset's bundle once per JVM and cache it by integration test path (BUILT_BUNDLES). Many classes -- and all of NyctRandomIntegrationTest's methods -- share a dataset, so this removes the bulk of redundant builds. A fresh Spring context + GtfsRealtimeSource is still created per method, so realtime state (route cancellations, dynamic blocks) stays isolated. - Run test classes in parallel JVMs via surefire forkCount=2 / reuseForks (overridable with -Dintegration.forkCount). - Give each bundle build a process-unique temp dir so parallel forks can't collide on a same-millisecond timestamp. Locally the module drops from ~13:51 to ~4:20 of test time and bundle builds from 12 to 5, with no OOM at forkCount=2.
|
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughIntegration test parallelism is enabled by three coordinated changes: ChangesParallel Integration Test Optimization
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
The
onebusaway-gtfsrt-integration-testsmodule was the dominant cost in CI — ~13:51 of an ~18 min job, and the source of ~67k log lines. Two causes:AbstractGtfsRealtimeIntegrationTest's@Beforerebuilt the full GTFS transit-graph bundle (the expensive part) before every test method, and the suite ran serially.BUILT_BUNDLES). Multiple classes share a dataset (nyct_wrong_way,st_duplicated_trips, …), and all ofNyctRandomIntegrationTest's active methods share one — so this removes the bulk of redundant builds. Only the immutable on-disk bundle is shared; a fresh Spring context +GtfsRealtimeSourceis still created per method, so realtime state that accumulates in context singletons (route cancellations, dynamic/added blocks) stays isolated.forkCount=2+reuseForks=true(overridable with-Dintegration.forkCount).Local results (this module): test time ~13:51 → ~4:20, bundle builds 12 → 5, no OOM at
forkCount=2.Test plan
mvn test -pl onebusaway-gtfsrt-integration-tests -am: 15 classes, 0 failures / 0 errors, same skip pattern as the prior CI runNyctRandomIntegrationTestbuilds the bundle once instead of 5×, all 5 active methods still pass (370s → 254s)OutOfMemoryErrorwithforkCount=2BundleBuilderuniqueness + pom)forkCount=2on the standard 4-core/16 GB runner, and end-to-end job wall-clockReview notes (non-blocking)
forkCount=2× full transit bundle was only validated on a dev machine. If CI OOMs, set-Dintegration.forkCount=1(the property is wired for exactly this).BundleBuilder's existing manual cross-run reuse (bundle.keep/bundle.index.json); they were left as separate mechanisms rather than unified, to keep the change scoped.-Dlog4j.configuration=flag, which is out of scope.Summary by CodeRabbit