Refactor scheduler discovery and unify JVM argument handling#105
Conversation
2c4c354 to
8fbd85a
Compare
There was a problem hiding this comment.
Pull request overview
This PR refactors the virtual-thread scheduler integration to improve class-loader compatibility (notably for fat JAR / container scenarios) by introducing a JDK-only bootstrap scheduler that discovers the real implementation via ServiceLoader, and updates build/docs/bench tooling to use the new scheduler entrypoint and unified JVM-args handling.
Changes:
- Added a new
bootstrapmodule (io.netty.loom.spi) containing the JDK-loadedNettySchedulerand aNettySchedulerSpiinterface discovered viaServiceLoader. - Moved the Netty-specific scheduling logic behind the SPI (
NettySchedulerProviderImpl) and registered it viaMETA-INF/services. - Updated documentation, tests, benchmarks, and the benchmark runner script to use
io.netty.loom.spi.NettySchedulerand to consolidate JVM argument handling (--jvm-args/SERVER_JVM_ARGS).
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Updates runtime flag docs to point to the new bootstrap scheduler class. |
| pom.xml | Adds the new bootstrap module and updates Surefire argLine scheduler class. |
| example-echo/pom.xml | Updates the scheduler implClass property to the new bootstrap entrypoint. |
| core/src/test/java/io/netty/loom/VirtualMultithreadIoEventLoopGroupTest.java | Switches tests to use the bootstrap NettyScheduler API. |
| core/src/test/java/io/netty/loom/NettySchedulerClassInitTest.java | Validates bootstrap scheduler availability via the new class. |
| core/src/test/java/io/netty/loom/ClassLoaderIsolationTest.java | Adds a class-loader isolation regression test for SPI discovery. |
| core/src/main/resources/META-INF/services/io.netty.loom.spi.NettySchedulerSpi | Registers the core provider implementation for ServiceLoader. |
| core/src/main/java/io/netty/loom/VirtualMultithreadIoEventLoopGroup.java | Uses bootstrap scheduler for availability checks and updates error text. |
| core/src/main/java/io/netty/loom/NettySchedulerProviderImpl.java | Converts the previous scheduler implementation into an SPI provider. |
| core/src/main/java/io/netty/loom/FifoEventLoopScheduler.java | Uses NettyScheduler.instance() from the bootstrap module. |
| core/pom.xml | Adds a dependency on the new bootstrap module. |
| bootstrap/src/main/java/io/netty/loom/spi/NettySchedulerSpi.java | Introduces SPI contract for provider implementations. |
| bootstrap/src/main/java/io/netty/loom/spi/NettyScheduler.java | Adds the JDK-loaded bootstrap scheduler that discovers the provider via ServiceLoader. |
| bootstrap/pom.xml | Defines the new JDK-only bootstrap module. |
| benchmarks/src/main/java/io/netty/loom/benchmark/SchedulerHandoffBenchmark.java | Updates benchmark forks to use the new scheduler implClass. |
| benchmarks/src/main/java/io/netty/loom/benchmark/NettySchedulerBenchmark.java | Updates benchmark forks to use the new scheduler implClass. |
| benchmark-runner/scripts/run-benchmark.sh | Unifies JVM arg handling and switches scheduler implClass to bootstrap. |
| benchmark-runner/README.md | Updates benchmark runner configuration docs for the unified --jvm-args behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The JDK's VirtualThread.loadCustomScheduler() uses ClassLoader.getSystemClassLoader(), which fails in Spring Boot fat JARs and app servers where application classes live under a non-standard class loader (e.g. LaunchedClassLoader). Split NettyScheduler into a thin bootstrap module (io.netty.loom.spi) with zero Netty dependencies and a core SPI implementation, following the JDBC driver discovery pattern: - bootstrap/ : NettyScheduler (JDK-loaded shim) + NettySchedulerSpi interface. Uses ServiceLoader with TCCL to discover the real implementation at runtime. - core/ : NettySchedulerProviderImpl (actual scheduling logic), registered via META-INF/services. The two modules use separate packages (io.netty.loom.spi vs io.netty.loom) to avoid split-package problems under JPMS. Includes ClassLoaderIsolationTest that reproduces the original ClassNotFoundException and proves ServiceLoader-based discovery works through a child-first class loader.
8fbd85a to
fa3ea32
Compare
…der in test - validateNettyAvailability() now distinguishes between "bootstrap not installed" (missing -D flag) and "bootstrap installed but no SPI provider found" (core JAR not on TCCL, missing META-INF/services). - ClassLoaderIsolationTest: use try-with-resources for URLClassLoader. - ServiceConfigurationError in the constructor is intentionally not caught: silent fallback would mask real misconfigurations. Fail-fast matches the JDK's own loadCustomScheduler() behavior.
|
@copilot review again? |
Re-reviewed on f920455. The earlier review items I raised are addressed, and I don’t have any new code changes to request from this pass. I also rechecked validation: the latest branch CI run for f920455 is in progress, while the previous Loom Build Tests run passed; local Maven verification in this sandbox is blocked because it only has Java 17 but this repo builds against Java 27 preview. |
|
There are still some issues when using the custom Loom virtual thread scheduler from a Spring Boot executable jar.I created a branch with both the reproduction and the fix: https://github.com/dreamlike-ocean/Netty-VirtualThread-Scheduler/tree/spring_bug Reproduction commit: 8356fbe So the scheduler class is physically in the fat jar, but not visible to the loader used by Fix commit: 8ad34ea This commit places the thin bootstrap scheduler classes in the outer jar as multi-release entries: The manifest has: So Loom can load the bootstrap scheduler successfully, while the real implementation still stays in |
…and application server environments - Add instructions for configuring classloaders in Spring Boot, OpenLiberty, WildFly, and other servers. - Document MRJAR-based solution for fat JAR deployments. - Credit contributor for identifying and fixing related issues.
|
Thanks @dreamlike-ocean I have added a doc section to explain how to handle it. Now waiting for OpenLiberty maintainers as well! |
This pull request introduces a new modular bootstrap layer for the Netty VirtualThread Scheduler, separating the system-classpath scheduler entrypoint from the actual Netty logic. It standardizes the JVM property for enabling the custom scheduler, updates documentation and usage throughout the project