Blocking Detection
The Blocking Detection integration helps to detect inadvertent calls of blocking code by coroutines.
Example: Calling an I/O library function blocks a CPU-bound thread.
Info
Blocking detection is available exclusively on the JVM via BlockHound. In can be enabled in common code, but has no effect on non-JVM platforms.
Getting started🔗
-
Add the integration's dependency to the common or JVM test source set:
-
Use the following
testConfigparameter at the appropriate point in your test element hierarchy:
Configuration🔗
By default, the Blocking Detection integration throws an error for suspicious blocking calls. To print detected blocking calls instead, use the following:
Blocking Detection can also be disabled:
Detection🔗
Blocking calls will be detected in coroutine threads which are expected not to block. Such threads are created by the default dispatcher as this example demonstrates:
private suspend fun blockInNonBlockingContext() {
withContext(Dispatchers.Default) {
@Suppress("BlockingMethodInNonBlockingContext")
Thread.sleep(2)
}
}
The BlockHound integration will by default produce an exception like this whenever it detects a blocking call:
reactor.blockhound.BlockingOperationError: Blocking call! java.lang.Thread.sleep0
at de.infix.testBalloon.integration.blockingDetection.TestBalloonBlockHoundIntegration.applyTo$lambda$0$0(Integration.jvm.kt:78)
at reactor.blockhound.BlockHound$Builder.lambda$install$8(BlockHound.java:488)
at reactor.blockhound.BlockHoundRuntime.checkBlocking(BlockHoundRuntime.java:89)
at java.base/java.lang.Thread.sleep0(Thread.java)
at java.base/java.lang.Thread.sleep(Thread.java:509)
Whenever a blocking call is detected, you can
- replace the call with a non-blocking one (using a coroutine-aware library), or
- schedule the calling coroutine to run on a separate I/O thread (e.g. via
Dispatchers.IO), or - add an exception if the blocking is harmless (see below).
Customization🔗
To customize BlockHound, familiarize yourself with the BlockHound documentation.
Exceptions for blocking calls considered harmless can be added via a separate BlockHoundIntegration class like this:
import reactor.blockhound.BlockHound
import reactor.blockhound.integration.BlockHoundIntegration
class MyBlockHoundIntegration : BlockHoundIntegration {
override fun applyTo(builder: BlockHound.Builder): Unit = with(builder) {
allowBlockingCallsInside("org.slf4j.LoggerFactory", "performInitialization")
}
}
In order to allow BlockHound to auto-detect and load the integration, add its fully qualified class name to a service provider configuration file
resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration.