A Spring Boot + gRPC demo app showing blockless in action.
| RPC | Blockless feature | What it proves |
|---|---|---|
Greet |
Blockless.get() |
Wait on a slow downstream without blocking platform threads |
GreetAll |
Parallel.map() + withMaxConcurrency(5) |
Bounded parallel fan-out with gRPC + MDC context propagation |
GreetSafe |
Parallel.toEither() |
Partial failure handling — some succeed, some fail, results stay in order |
Context propagation: SLF4J MDC traceId and gRPC Context flow from the
incoming request through virtual threads via Slf4jMdcContextPropagator
and GrpcContextPropagator.
mvn spring-boot:rungRPC server starts on port 9090.
Requires grpcurl.
Single greeting — Blockless.get():
grpcurl -plaintext -d '{"name": "Toothless"}' localhost:9090 org.pjlabs.example.GreetingService/GreetFan-out — Parallel.map() with bounded concurrency:
grpcurl -plaintext -d '{"names": ["Alpha", "Beta", "Gamma", "Delta", "Epsilon"]}' localhost:9090 org.pjlabs.example.GreetingService/GreetAllPartial failure — Parallel.toEither(), pass "FAIL" to trigger an error:
grpcurl -plaintext -d '{"names": ["Alpha", "FAIL", "Gamma"]}' localhost:9090 org.pjlabs.example.GreetingService/GreetSafeWith trace-id — context propagation through virtual threads:
grpcurl -plaintext -H 'trace-id: dragon-trace-789' -d '{"names": ["A", "B", "C"]}' localhost:9090 org.pjlabs.example.GreetingService/GreetAllCheck the app logs to see thread names, virtual thread info, and traceId flowing through.
mvn test8 tests covering:
Blockless.get()round-tripParallel.map()fan-out correctness and parallelism (5 x 100ms in <400ms)Parallel.toEither()partial failure and all-success cases- MDC traceId propagation from gRPC header to each virtual thread
- Java 21+
- Maven
Apache 2.0