Java agent to detect blocking calls from non-blocking threads.
BlockHound will transparently instrument the JVM classes and intercept blocking calls (e.g. IO) if they are performed from threads marked as "non-blocking operations only" (ie. threads implementing Reactor's NonBlocking
marker interface, like those started by Schedulers.parallel()
). If and when this happens (but remember, this should never happen! 😜), an error will be thrown. Here is an example:
// Example.java BlockHound.install(); Mono.delay(Duration.ofSeconds(1)) .doOnNext(it -> { try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } }) .block();
Will result in:
reactor.blockhound.BlockingOperationError: Blocking call! java.lang.Thread.sleep
at java.base/java.lang.Thread.sleep(Native Method)
at com.example.Example.lambda$exampleTest$0(Example.java:16)
Note that it points to the exact place where the blocking call got triggered. In this example it was Example.java:16
.
Download it from Maven Central repositories (stable releases only) or repo.spring.io:
Gradle
repositories { mavenCentral() // maven { url 'https://repo.spring.io/milestone' } // maven { url 'https://repo.spring.io/snapshot' } } dependencies { testImplementation 'io.projectreactor.tools:blockhound:$LATEST_RELEASE' // testImplementation 'io.projectreactor.tools:blockhound:$LATEST_MILESTONE' // testImplementation 'io.projectreactor.tools:blockhound:$LATEST_SNAPSHOT' }with Kotlin DSL
repositories { mavenCentral() // maven("https://repo.spring.io/milestone") // maven("https://repo.spring.io/snapshot") } dependencies { testImplementation("io.projectreactor.tools:blockhound:$LATEST_RELEASE") // testImplementation("io.projectreactor.tools:blockhound:$LATEST_MILESTONE") // testImplementation("io.projectreactor.tools:blockhound:$LATEST_SNAPSHOT") }
Maven
<dependencies> <dependency> <groupId>io.projectreactor.tools</groupId> <artifactId>blockhound</artifactId> <version>$LATEST_RELEASE</version> </dependency> </dependencies>
Where:
for JDK 13+, it is no longer allowed redefining native methods. So for the moment, as a temporary work around, please use the -XX:+AllowRedefinitionToAddDeleteMethods
jvm argument:
Maven
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> <configuration> <argLine>-XX:+AllowRedefinitionToAddDeleteMethods</argLine> </configuration> </plugin>
Gradle
tasks.withType(Test).all { if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { jvmArgs += [ "-XX:+AllowRedefinitionToAddDeleteMethods" ] } }with Kotlin DSL
tasks.withType<Test>().all { if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { jvmArgs("-XX:+AllowRedefinitionToAddDeleteMethods") } }
Although BlockHound supports the SPI mechanism to integrate with, it comes with a few built-in integrations:
reactor-core
version 3.3.0, there is a built-in integration in Reactor itself that uses the SPI.See the docs.
Licensed under Apache Software License 2.0
Sponsored by Pivotal
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4