-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix #178 by introducing a BuilderAllowSpec intermediate step in the builder #179
Conversation
This commit introduces a STATIC_INITIALIZER constant in BlockHound, so it becomes easier to discover that the features relying on the `String methodName` parameter can work with `<clinit>` for static initializer. Additionally, this is documented in the customization examples and used in the StaticInitTest. Fixes #178.
23817ed
to
d635dbf
Compare
(oops, the branch is misnamed and should refer to #178 rather than 176) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea but could you please also add a paragraph in the Javadoc of allow and disallow that explicitly mentions this scenario?:
<p>To allow blocking in the static initializer block of a class, use the constant `{@link #STATIC_INITIALIZER} as the method name`.
Done 👍 |
* The special methodName that should be used in e.g. {@link Builder#allowBlockingCallsInside(String, String)} | ||
* when one wants to reference the static initializer block rather than a class method. | ||
*/ | ||
public static final String STATIC_INITIALIZER = "<clinit>"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this constant would never change (part of the JVM's spec), I do not feel that it makes sense to introduce it. We could keep the docs section (for both <clinit>
and <init>
), but the constant will only create an unnecessary noise in the public signature of this class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. Mentioning the reserved method name in the doc indeed feels like a minimum viable solution, but feels slightly less user-friendly than providing a safe constant which can quickly be auto-completed. Would it limit the noise drawback if the constant was defined in Builder
instead of BlockHound
? @rstoyanchev as a user, what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also prefer an explicit API with documentation as a minimum. That said, thinking more about the constant it also gets slightly verbose with the class name included, and it's not automatically discoverable.
What about adding a sub-builder step:
builder
.allowBlockingCallsInside("com.example.ClassA", "methodA")
.allowBlockingCallsInside("com.example.ClassB").staticInitializers()
.disallowBlockingCallsInside("com.example.ClassC").constructors();
The sub-builder something like:
interface BlockingCallSpec {
BlockHound.Builder staticInitializers();
BlockHound.Builder constructors();
}
Or perhaps an enum after all?
builder
.allowBlockingCallsInside("com.example.ClassA", "methodA")
.allowBlockingCallsInside("com.example.ClassB", BlockHound.TargetType.STATIC_INITIALIZER)
.disallowBlockingCallsInside("com.example.ClassC", BlockHound.TargetType.CONSTRUCTORS);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exploring the builder idea in this PR and the enum in #184
@rstoyanchev @bsideup dc9186b introduces a |
* {@link Builder#allowBlockingCallsInside(String, String)}. One MUST specify at least one | ||
* allowed method for it to have an effect on the configuration. | ||
*/ | ||
public class BuilderAllowSpec { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see anything for "Disallow". Doesn't that need the same? The same builder could support both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it could, but I wasn't able to test the disallow feature. Either I misunderstand it or there is something wrong with the feature (which isn't tested)... so for now I prefer to focus on the allow-static-initializer case which is demonstrably supported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw that and didn't find it crystal clear.
The following tests fail:
public class BlockingDisallowTest {
static {
BlockHound.install(b -> b
.disallowBlockingCallsInside("reactor.core.publisher.Flux", "just")
.disallowBlockingCallsInside(NonBlockingClass.class.getName(), "example")
);
}
@Test
public void shouldDisallowFluxJust() {
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() ->
Mono.just("one")
.publishOn(Schedulers.parallel())
.flatMapMany(i -> Flux.just("one", "two"))
.blockLast()
)
.withCauseInstanceOf(BlockingOperationError.class);
}
@Test
public void shouldDisallowNonBlocking() {
NonBlockingClass nbc = new NonBlockingClass();
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() ->
Mono.fromCallable(nbc::example)
.subscribeOn(Schedulers.parallel())
.block()
)
.withCauseInstanceOf(BlockingOperationError.class);
}
static class NonBlockingClass {
String example() {
return "example";
}
}
}
What am I missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You seem to be missing how BlockHound works, see https://github.com/reactor/BlockHound/blob/master/docs/how_it_works.md and especially "Blocking call decision".
tl;dr: disallowBlockingCallsInside
disallows blocking calls inside provided method (as per the API method's name). It does not, however, mark the method as blocking, so your Flux.just
or NonBlockingClass.example
makes no sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not support the idea of adding DSL just for the sake of marking static constructors.
Also, disallowing should be supported.
Last but not least, it seems that static constructor is the only type of methods added by it, which only confirms that a dedicated DSL is an overkill
This commit introduces a STATIC_INITIALIZER constant in BlockHound, soit becomes easier to discover that the features relying on the
String methodName
parameter can work with<clinit>
for staticinitializer.
Additionally, this is documented in the customization examples and
used in the StaticInitTest.
Fixes #178.