Customization
January 26, 2023 · View on GitHub
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().
Marking more methods as blocking
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.
(Dis-)allowing blocking calls inside methods
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.
Custom blocking method callback
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.
Custom non-blocking thread predicate
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-"))
});
⚠️ Warning: do not ignore the 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.