Webflux 找出項目中阻塞(Blocking call)的方法

0. 為什么需要找到Blocking call

我們使用reactor編程時吆鹤,其目的就是希望我們的程序符合異步非阻塞的模型,為了達到這個目的巍棱,我們希望我們程序中所有的方法都是非阻塞的方法(理想狀態(tài))雇寇,比如我們在處理JDBC鏈接時,會考慮使用Schedulers來包裹或是使用R2DBC胶果,那么在響應式編程中,我們會遇到形形色色的阻塞方法斤斧,此時早抠,我們就需要用合理的方式處理它們了.

1. 解決方案

BlockHound

2. Git 地址

https://github.com/reactor/BlockHound

3. 大致原理

類似于Java代理,再入口函數(shù)調(diào)用前被JVM加載撬讽,一旦BlockHound啟動蕊连,其將標記阻塞方法(例如: sleep()) .并改變其behaviour而拋出一個Error

4. 引入BlockHound

在自己的工程中引入BlockHound

4.1. maven

<dependency>
  <groupId>io.projectreactor.tools</groupId>
  <artifactId>blockhound-junit-platform</artifactId>
  <version>1.0.0.RC1</version>
  <scope>test</scope>
</dependency>

4.2. Gradle

repositories {
mavenCentral()
// maven { url 'https://repo.spring.io/milestone' }
// maven { url 'https://repo.spring.io/snapshot' }
}

dependencies {
testCompile 'io.projectreactor.tools:blockhound:$LATEST_RELEASE'
// testCompile 'io.projectreactor.tools:blockhound:$LATEST_MILESTONE'
// testCompile 'io.projectreactor.tools:blockhound:$LATEST_SNAPSHOT'
}

5. 使用示例

public class DetectBlockingCall {

    @BeforeEach
    void setUp() {
        // 1. 初始化BlockHound
        BlockHound.install();
    }

    // 2. 定義一個阻塞方法
    void blockingCall() {
        Mono.delay(Duration.ofSeconds(1))
                .doOnNext(it -> {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                })
                .block();
    }

    @Test
    void blockHoundSimpleTest() {
        //3. 調(diào)用阻塞方法
        Throwable throwable = Assertions.assertThrows(Throwable.class, this::blockingCall);
        //4. 驗證阻塞方法是否拋出異常
        Assertions.assertTrue(throwable.getMessage().contains("Blocking call!"));
    }
}

在這個示例中,第一步加載BlockHound實際是可以省略的锐秦,因為我們引入BlockHound到junit 實際是已經(jīng)被預加載, 大家可以去除這一步再次執(zhí)行測試代碼嘗試

6. 構(gòu)建項目時自動執(zhí)行BlockHound

往往我們希望我們自身的項目可以自動執(zhí)行BlockHound咪奖,從而每次運行測試代碼便可以知道我們的代碼問題在哪里盗忱,那么這里提供一種思路酱床,即使用項目構(gòu)建工具來執(zhí)行BlockHound, 以Gradle為例.

6.1. 編寫定制化BlockHound模塊 (當然你可以不定制化)

在開發(fā)中,往往我們不可避免的使用部分部分阻塞方法趟佃,那么此時我們需要測試時排除這些方法. 此時我們可以定義一些定制化類扇谣,例如:

新建一個工程com.test.support昧捷, 新建一個模塊叫做blockhound-integration, 然后新建一個Log的忽略類

public class LogBlockHoundIntegration implements BlockHoundIntegration {
// 使用系統(tǒng)變量來達到開關(guān)的目的
    private static final boolean ENABLED = Boolean.parseBoolean(System.getProperty("LogBlockHoundIntegration.enabled", Boolean.FALSE.toString()));
    @Override
    public void applyTo(BlockHound.Builder builder) {
        if (!ENABLED) {
            return;
        }
        // 加入要忽略的阻塞方法
builder.allowBlockingCallsInside(
                "ch.qos.logback.classic.Logger",
                "buildLoggingEventAndAppend");
    }
}

6.2. 定義測試監(jiān)聽類

實現(xiàn)TestExecutionListener, 靜態(tài)加載BlockHound,使得所有測試方法都需要加載BlockHound

public class BlockHoundTestExecutionListener implements TestExecutionListener {
    static {
        BlockHound.install(builder -> {
            builder.blockingMethodCallback(method -> {
                Error error = new BlockingOperationError(method);
                error.printStackTrace(System.err);
                throw error;
            });
        });
    }
}

6.3. 在自己模塊的gradle文件中定義方法罐寨,引入我們的定義及默認的junit平臺

ext {
    // add helper to activate Reactor BlockHound, https://github.com/reactor/BlockHound
    useReactorBlockHound = { ->
        project.dependencies {
            testRuntimeOnly 'com.test.support:blockhound-integration', 'org.junit.platform:junit-platform-launcher'
        }
    }
}

6.4. 定義執(zhí)行操作入口

build.gradle 中插入

subprojects { subproject ->
  subproject.useReactorBlockHound()
}

// 打開我們自己定義的生效類

tasks.withType(Test) {
        // ignore the blocking nature of Log
        systemProperty 'LogBlockHoundIntegration.enabled', 'true'
    }

至此靡挥,我們基本可以滿足gradle項目開發(fā)中所需要的自動化測試了。如果你在使用maven鸯绿,可以構(gòu)建自己的maven插件跋破,來實現(xiàn)自動化流程,具體邏輯與gradle是類似的

6. 結(jié)論

響應式編程是基于我們想充分利用異步非阻塞而產(chǎn)生的一種設(shè)計瓶蝴,但如今我理解技術(shù)正處于一個轉(zhuǎn)型期毒返,往往我們會遇到阻塞+非阻塞的囧境,為了解決這個問題舷手,今天引入BlockHound工具來探測我們程序中潛在的阻塞API拧簸,使我們更快的發(fā)現(xiàn)問題并做出調(diào)整.

7. ref

https://medium.com/@domenicosibilio/blockhound-detect-blocking-calls-in-reactive-code-before-its-too-late-6472f8ad50c1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者男窟。
  • 序言:七十年代末盆赤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子歉眷,更是在濱河造成了極大的恐慌牺六,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姥芥,死亡現(xiàn)場離奇詭異兔乞,居然都是意外死亡,警方通過查閱死者的電腦和手機凉唐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門庸追,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人台囱,你說我怎么就攤上這事淡溯。” “怎么了簿训?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵咱娶,是天一觀的道長。 經(jīng)常有香客問我强品,道長膘侮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任的榛,我火速辦了婚禮琼了,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己雕薪,他們只是感情好昧诱,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著所袁,像睡著了一般盏档。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上燥爷,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天蜈亩,我揣著相機與錄音,去河邊找鬼前翎。 笑死勺拣,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的鱼填。 我是一名探鬼主播药有,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼苹丸!你這毒婦竟也來了愤惰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赘理,失蹤者是張志新(化名)和其女友劉穎宦言,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體商模,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡奠旺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了施流。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片响疚。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瞪醋,靈堂內(nèi)的尸體忽然破棺而出忿晕,到底是詐尸還是另有隱情,我是刑警寧澤银受,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布践盼,位于F島的核電站,受9級特大地震影響宾巍,放射性物質(zhì)發(fā)生泄漏咕幻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一顶霞、第九天 我趴在偏房一處隱蔽的房頂上張望肄程。 院中可真熱鬧,春花似錦、人聲如沸绷耍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽褂始。三九已至,卻和暖如春描函,著一層夾襖步出監(jiān)牢的瞬間崎苗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工舀寓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留胆数,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓互墓,卻偏偏與公主長得像必尼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子篡撵,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容