비동기 처리 절차 흐름 중간에 하나라도 동기가 포함되어 있으면 전체 성능에 치명적이며, 비동기 프로그램 경험 시 동기식 프로그래밍 대비 디버깅의 어려움을 겪는다. 배포 후가 아닌 개발 과정에서 빠르게 원인을 찾도록 하는 도구들을 사용하는 것이 효과적이다.
Blockhound는 논블로킹 스레드 환경에서 블로킹 되는 조건을 찾아주는 도구이다.
로컬 개발 환경이나 테스트 코드를 실행할 때 함께 동작시키는 게 일반적이며, 대부분 테스트 코드를 실행할 때 함께 사용한다.
로컬 개발 환경에 반영
implementation ‘io.projectreactor.tools:blockhound:$LATEST_RELEASE’
테스트 코드에 반영
testImplementation ‘io.projectreactor.tools:blockhound:$LATEST_RELEASE’
@SpringBootApplication
public class Webflux1Application implements ApplicationRunner {
public static void main(String[] args) {
**BlockHound.install();**
SpringApplication.run(Webflux1Application.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
Mono.delay(Duration.ofSeconds(1))
.doOnNext(it -> {
try {
**Thread.sleep(100); // 오류 검출**
} catch (InterruptedException e){
throw new RuntimeException(e);
}
})
.subscribe();
}
}

Blockhound.install() 메서드를 호출하면 그 다음부터 코드 검출을 진행하게 된다.
Blockhound는 애플리케이션 코드에 자동으로 블로킹을 검출하는 코드를 삽입하게 되고, 이를 통해 블로킹을 검출하게 되면 오류로 콘솔에 출력해주는 흐름을 갖는다.
JDK 13 이후부터는 다음 JVM 옵션을 추가해야 한다.
-XX:+AllowRedefinitionToAddDeleteMethods
tasks.withType(Test).all {
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) {
jvmArgs += ["-XX:+AllowRedefinitionToAddDeleteMethods"]
}
}
dependencies {
...
**testImplementation** 'io.projectreactor.tools:blockhound:1.0.8.RELEASE'
}
// 테스트 코드
@AutoConfigureWebTestClient
@WebFluxTest(UserController.class)
class UserControllerTest {
static {
BlockHound.install();
}
...
@Test
void blockHoundTest() {
StepVerifier.create(Mono.delay(Duration.ofSeconds(1))
.doOnNext(it -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}))
.verifyComplete();
}
