reactor / BlockHound

Java agent to detect blocking calls from non-blocking threads.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Provide API or document how to allow/disallow blocking inside constructors

rstoyanchev opened this issue · comments

There is no guidance I could find on how to allow/disallow blocking in a constructor or static initializer. There is one test that shows how to do it for a static initializer but it would be nicer if it was easier to find. One option could be a dedicated method, e.g. allowBlockingCallsInsideConstructor(String classname), or otherwise provide guidance in the Javadoc on allowBlockingCallsInside and a mention on the Customizations page.

This one is interesting. I naively tried to use <init> as the method name, but ByteBuddy complaints that:

java.lang.IllegalStateException: Cannot catch exception during constructor call for public com.example.ConstructorInitTest$ClassWithThrowingConstructor()

After toying a little with the AllowAdvice, it seems to work if we remove the onThrowable part in the method exit advice:

@Advice.OnMethodExit(onThrowable = Throwable.class)

@bsideup any insight to share? As far as I understand this is so a throwing method is caught, but do we really need that? Isn't the allowance working by marking the thread as blocking-friendly, so the exception is never actually raised?

Note that we could have a slightly different Advice for constructors, if needed.

@rstoyanchev the static initializer works already, so we could indeed either document the <clinit> special name, or introduce an alias method like allowBlockingCallsInsideStaticInitializerOf(String className).

The challenge is that with a pair of methods to allow/disallow, it would take 6 similarly named methods [dis]allowBlockingCallsInside to cover methods, constructors, and static initializers. Not the end of the world but maybe there is a better way to collect this input.

Maybe methodName as a vararg in which case if it is empty or null, it's taken to apply to class constructors, which would only leave static initializers as an extra pair. Or perhaps an extra pair of methods with an enum for input.

for the constructor, we have to defer a bit because it is not even sure allowBlockingCallsInside can work with constructors due to the aforementioned ByteBuddy limitation...

let me split this issue in two. this one will be dedicated to the constructor part, and I'll open an issue dedicated to improving discoverability of the static initializer part.

@simonbasle

As far as I understand this is so a throwing method is caught, but do we really need that?

I can assure you that nothing in BlockHound is done without a reason.
Instrumentation is a very sensible topic, with an entry barrier. I would be happy to explain how it all works under the good, but, due to the lack of time, for now, I would recommend referring to the publicly available source of information on the topic of instrumentation (e.g. ByteBuddy's issues, Stack Overflow, articles)

@bsideup I think it would be good to know. Are constructors supported? It seems the answer is no, but maybe you can clarify. If they are not, do you see a way for that to be supported, i.e. should we create a separate issue?

@rstoyanchev let's create an issue for the constructors support. Java does not support try {} finally {} around the super() calls, and that's what ByteBuddy attempts to do and fails, but perhaps we could go lower level (with ASM) and add try {} finally {} around the rest of the constructor

note that this is intended as the issue for constructor support.

I think documenting the current status quo is a sufficient for this issue, for me at least. Having a different issue for constructor support allows for that to be addressed separately, especially since it is more involved. The documentation could even reference such a separate issue.