BlockHound provides three means of usage:
BlockHound.install()- will useServiceLoaderto load all knownreactor.blockhound.integration.BlockHoundIntegrationsBlockHound.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.