Bootstrap refactoring#114
Conversation
c58d252 to
7ef1b57
Compare
|
this script still uses the old io.netty.loom.spi.NettyScheduler class, so it should be updated to io.netty.loom.scheduler.NettyScheduler. |
|
So @dreamlike-ocean this change, despite good seems now blocked by |
try this dreamlike-ocean@ae69a9b |
|
@dreamlike-ocean thanks for checking! |
Move all Netty-independent scheduling classes from core to bootstrap under io.netty.loom.scheduler package. Eliminates the per-classloader singleton problem in app servers (JBoss/Liberty) where multiple classloaders would create duplicate carrier groups. What moved to bootstrap: - NettyScheduler (entry point, was in io.netty.loom.spi) - EventLoopScheduler (carrier loop, run queue, work stealing) - EventLoopSchedulerGroup (carrier pool) - SchedulerJfrUtil + 4 JFR events - jctools as a regular dependency (shade blocked by ASM/Java 27) What changed: - SPI eliminated: NettyScheduler directly routes onStart/onContinue - Eager carrier pool creation in NettyScheduler constructor - NettyScheduler reference passed explicitly (no partial publication) - Tests moved to io.netty.loom.scheduler package for visibility - SchedulerJfrUtil split: scheduler events in bootstrap, Netty I/O events (NettyJfrUtil) stay in core JVM flag changed: -Djdk.virtualThreadScheduler.implClass=io.netty.loom.scheduler.NettyScheduler
NettyRunTasksEvent and the runNonBlockingTasks wrapper methods in both event loop groups are dead code since the poller loop simplification. Remove the event class, JFR util methods, JFC config entry, timeline script reference, and benchmark README entry.
Raw Netty HTTP server with epoll pinned pollers demonstrating blocking VT handlers, structured concurrency with carrier affinity, and carrier info in responses. No Spring Boot, no external dependencies. Endpoints: GET / - blocking handler (50ms), returns VT + carrier info GET /parallel - StructuredTaskScope fork/join on same carrier
7ef1b57 to
3679a1d
Compare
Replace direct field access on SchedulingContext with named methods: - home() instead of .eventLoopScheduler - type() instead of .type - mountedOn(carrier) instead of .runningScheduler = carrier - setVThreadId(id) instead of .vThreadId = id Fields stay package-private (the class itself is package-private). The accessors add readability, not encapsulation.
3679a1d to
d8eaf41
Compare
There was a problem hiding this comment.
Pull request overview
Refactors the project so the Netty-independent scheduling core (custom NettyScheduler, EventLoopScheduler*, scheduler JFR events) lives in the bootstrap module under io.netty.loom.scheduler, eliminating the previous ServiceLoader SPI and updating docs/examples/benchmarks to the new scheduler flag and package layout.
Changes:
- Move scheduler core + scheduler JFR events into
netty-virtualthread-bootstrapand remove the SPI provider/discovery mechanism. - Update Netty integration layer to depend on
io.netty.loom.scheduler.*directly and simplify availability checks. - Refresh docs, example-echo, and benchmark runner scripts/configs to the new scheduler class name and removed JFR events.
Reviewed changes
Copilot reviewed 35 out of 35 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Updates scheduler flag, module roles, and deployment/classloader guidance for bootstrap-first scheduler. |
| pom.xml | Updates surefire JVM argLines to point at io.netty.loom.scheduler.NettyScheduler. |
| example-echo/src/main/java/io/netty/loom/example/EchoServer.java | Reworks example into an epoll-based HTTP server demonstrating carrier affinity + structured concurrency. |
| example-echo/README.md | Updates example documentation and run instructions for the new scheduler/epoll setup. |
| example-echo/pom.xml | Switches example dependencies/plugins away from Spring Boot and adds epoll native transport dependency. |
| core/src/test/java/io/netty/loom/scheduler/VirtualIoNativePollerEventLoopGroupTest.java | Adjusts test package and updates API usage to new scheduler helpers. |
| core/src/test/java/io/netty/loom/scheduler/NettySchedulerClassInitTest.java | Adjusts test package for bootstrap scheduler init/availability. |
| core/src/test/java/io/netty/loom/ClassLoaderIsolationTest.java | Removes SPI-era classloader isolation test (no longer applicable). |
| core/src/main/resources/META-INF/services/io.netty.loom.spi.NettySchedulerSpi | Removes ServiceLoader registration (SPI removed). |
| core/src/main/java/io/netty/loom/VirtualIoNioPollerEventLoopGroup.java | Switches to bootstrap scheduler APIs; removes SPI-based availability checks; updates JFR util usage. |
| core/src/main/java/io/netty/loom/VirtualIoNativePollerEventLoopGroup.java | Switches to bootstrap scheduler APIs; removes SPI-based availability checks; updates JFR util usage. |
| core/src/main/java/io/netty/loom/VirtualIoEventLoopGroup.java | Imports bootstrap EventLoopSchedulerGroup for default carrier selection. |
| core/src/main/java/io/netty/loom/NettySchedulerProviderImpl.java | Removes SPI provider implementation (logic now in bootstrap scheduler). |
| core/src/main/java/io/netty/loom/NettyJfrUtil.java | Replaces old Spring Boot entrypoint content with Netty JFR utility for run-I/O events. |
| core/src/main/java/io/netty/loom/jfr/NettyRunTasksEvent.java | Removes the Netty “Run Tasks” JFR event class. |
| core/pom.xml | Removes jctools-core dependency from core (moved to bootstrap). |
| bootstrap/src/main/java/io/netty/loom/spi/NettySchedulerSpi.java | Removes SPI interface. |
| bootstrap/src/main/java/io/netty/loom/spi/NettyScheduler.java | Removes SPI-based bootstrap shim scheduler. |
| bootstrap/src/main/java/io/netty/loom/scheduler/SchedulerJfrUtil.java | Moves scheduler JFR util into bootstrap scheduler package and removes Netty task/run-I/O event helpers. |
| bootstrap/src/main/java/io/netty/loom/scheduler/NettyScheduler.java | Adds new bootstrap scheduler implementation that eagerly creates the carrier pool and routes tasks directly. |
| bootstrap/src/main/java/io/netty/loom/scheduler/jfr/WorkStealEvent.java | Moves scheduler JFR event package to io.netty.loom.scheduler.jfr. |
| bootstrap/src/main/java/io/netty/loom/scheduler/jfr/VirtualThreadTaskSubmitEvent.java | Moves scheduler JFR event package to io.netty.loom.scheduler.jfr. |
| bootstrap/src/main/java/io/netty/loom/scheduler/jfr/VirtualThreadTaskRunsEvent.java | Moves scheduler JFR event package to io.netty.loom.scheduler.jfr. |
| bootstrap/src/main/java/io/netty/loom/scheduler/jfr/VirtualThreadTaskRunEvent.java | Moves scheduler JFR event package to io.netty.loom.scheduler.jfr. |
| bootstrap/src/main/java/io/netty/loom/scheduler/EventLoopSchedulerGroup.java | Reworks singleton creation to come from NettyScheduler (bootstrap global), not SPI init. |
| bootstrap/src/main/java/io/netty/loom/scheduler/EventLoopScheduler.java | Moves scheduler core into bootstrap package; adjusts internals for new scheduler wiring and API exposure. |
| bootstrap/pom.xml | Adds jctools + shade configuration to embed/relocate it into the bootstrap artifact; adjusts surefire executions. |
| benchmarks/src/main/java/io/netty/loom/benchmark/SchedulerHandoffBenchmark.java | Updates benchmark JVM args to new scheduler implClass. |
| benchmarks/src/main/java/io/netty/loom/benchmark/NettySchedulerBenchmark.java | Updates benchmark JVM args to new scheduler implClass. |
| benchmark-runner/src/main/java/io/netty/loom/benchmark/runner/HandoffHttpServer.java | Updates imports to bootstrap EventLoopSchedulerGroup. |
| benchmark-runner/scripts/run-benchmark.sh | Removes NettyRunTasks event references and updates scheduler implClass flag. |
| benchmark-runner/scripts/jfr/netty-loom.jfc | Removes NettyRunTasks event configuration. |
| benchmark-runner/scripts/jfr/JfrToTimeline.java | Removes NettyRunTasks from parsed event list. |
| benchmark-runner/README.md | Updates supported event list and scheduler implClass example. |
| BACKLOG.md | Removes backlog document from repo. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (HttpUtil.isKeepAlive(request)) { | ||
| response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); | ||
| } | ||
| ctx.writeAndFlush(response); | ||
| if (!HttpUtil.isKeepAlive(request)) { | ||
| ctx.close(); | ||
| } |
| <shadedPattern>io.netty.loom.scheduler</shadedPattern> | ||
| </relocation> | ||
| </relocations> | ||
| <createDependencyReducedPom>false</createDependencyReducedPom> |
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-shade-plugin</artifactId> | ||
| <version>3.6.2</version> | ||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.ow2.asm</groupId> | ||
| <artifactId>asm</artifactId> | ||
| <version>9.10.1</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.ow2.asm</groupId> | ||
| <artifactId>asm-commons</artifactId> | ||
| <version>9.10.1</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.ow2.asm</groupId> | ||
| <artifactId>asm-tree</artifactId> | ||
| <version>9.10.1</version> | ||
| </dependency> | ||
| </dependencies> | ||
| <executions> | ||
| <execution> | ||
| <phase>package</phase> | ||
| <goals> | ||
| <goal>shade</goal> | ||
| </goals> | ||
| <configuration> | ||
| <artifactSet> | ||
| <includes> | ||
| <include>org.jctools:jctools-core</include> | ||
| </includes> | ||
| </artifactSet> | ||
| <relocations> | ||
| <relocation> | ||
| <pattern>org.jctools</pattern> | ||
| <shadedPattern>io.netty.loom.scheduler</shadedPattern> | ||
| </relocation> | ||
| </relocations> | ||
| <createDependencyReducedPom>false</createDependencyReducedPom> | ||
| </configuration> | ||
| </execution> | ||
| </executions> | ||
| </plugin> |
Move scheduling core to bootstrap module
Moves all Netty-independent scheduling classes (
EventLoopScheduler,EventLoopSchedulerGroup, JFR events) fromcoretobootstrapunderio.netty.loom.scheduler. Eliminates the SPI —NettySchedulerdirectly routesonStart/onContinueto carriers. Carrier pool is created eagerly at JVM startup.Why:
EventLoopSchedulerGroup.<clinit>is per-classloader. In app servers (JBoss, Liberty) or Spring Boot fat JARs with multiple classloaders, each gets its own carrier group. Additionally,instanceof SchedulingContextreturnsfalseacross classloaders (differentClassobjects), causing VTs to silently fall back to ForkJoinPool — no error, just lost carrier affinity. Moving to bootstrap (system classloader) guarantees one carrier pool and oneSchedulingContextclass identity per JVM.Trade-off: bootstrap now depends on jctools (
MpscUnboundedArrayQueue). On master, jctools stays incore(app classloader) — no version conflict risk. With this change, jctools must be on the system classpath alongside bootstrap, which could conflict if the application uses a different jctools version. The proper fix is shading jctools into the bootstrap JAR, butmaven-shade-plugindoes not yet support Java 27 class files (ASM stops at major version 70). Once ASM catches up, jctools should be shaded to eliminate this risk.JVM flag changed:
-Djdk.virtualThreadScheduler.implClass=io.netty.loom.scheduler.NettyScheduler