BlockHound provides three means of usage:
BlockHound.install()
- will useServiceLoader
to load all knownreactor.blockhound.integration.BlockHoundIntegration
sBlockHound.install(BlockHoundIntegration... integrations)
- same asBlockHound.install()
, but adds user-provided integrations to the list.BlockHound.builder().install()
- will create a new builder, without discovering any integrations.
You may install them manually by usingBlockHound.builder().with(new MyIntegration()).install()
.
Builder#markAsBlocking(Class clazz, String methodName, String signature)
Builder#markAsBlocking(String className, String methodName, String signature)
Example:
builder.markAsBlocking("com.example.NativeHelper", "doSomethingBlocking", "(I)V");
Note that the signature
argument is
JVM's notation for the method signature.
Builder#allowBlockingCallsInside(String className, String methodName)
Builder#disallowBlockingCallsInside(String className, String methodName)
Example:
This will allow blocking method calls inside Logger#callAppenders
down the callstack:
builder.allowBlockingCallsInside(
"ch.qos.logback.classic.Logger",
"callAppenders"
);
While this disallows blocking calls unless there is an allowed method down the callstack:
builder.disallowBlockingCallsInside(
"reactor.core.publisher.Flux",
"subscribe"
);
Example using Allow/Disalow
The below example demonstrates how to allow the NonBlockingClass.outer()
method to block, but not
the NonBlockingClass.inner()
method, which is called by the outer()
method:
public class BlockingDisallowTest {
static {
BlockHound.install(b -> b
.allowBlockingCallsInside(NonBlockingClass.class.getName(), "outer")
.disallowBlockingCallsInside(NonBlockingClass.class.getName(), "inner")
);
}
static class NonBlockingClass {
String inner() {
try {
//if this trips BlockHound, the test fails (inner not in the stacktrace)
Thread.sleep(50);
}
catch (InterruptedException e) {
e.printStackTrace();
}
return "example";
}
String outer() {
try {
Thread.sleep(50);
}
catch (InterruptedException e) {
e.printStackTrace();
}
Thread.yield();
return inner();
}
}
The NonBlockingClass.outer()
method is allowed to block and all the methods called down the stack, except the inner()
method
which is called by the outer()
method.
Builder#blockingMethodCallback(Consumer<BlockingMethod> consumer)
By default, BlockHound will throw an error when it detects a blocking call.
But you can implement your own logic by setting a callback.
Example:
builder.blockingMethodCallback(it -> {
new Error(it.toString()).printStackTrace();
});
Here we dump the stacktrace instead of throwing the error, so that we do not alter an execution of the code.
Builder#nonBlockingThreadPredicate(Function<Predicate<Thread>, Predicate<Thread>> predicate)
If you integrate with exotic technologies, or implement your own thread pooling, you might want to mark those threads as non-blocking. Example:
builder.nonBlockingThreadPredicate(current -> {
return current.or(it -> it.getName().contains("my-thread-"))
});
current
predicate unless you're absolutely sure you know what you're doing.
Other integrations will not work if you override it instead of using Predicate#or
.