COLA異步任務重複執行?

最近在使用COLA框架自帶的異步任務時,發現每次執行異步都執行了兩次,如果一些沒有做冪等的接口,這樣是會有問題的,比如入庫操作之類的,就會造成數據重複入庫,造成嚴重bug。

帶着疑惑,開始了 bug 之旅。

1 問題發現

1、首先排查執行入口,是不是有兩個,發現只有一個;

2、調用入口的問題?直接通過controller調用handler,還是調用了兩次。

3、簡化代碼,把handler內的內容都刪掉,只有一個logger打印語句?結果還是打印了兩次。

但是這次,發現logger的線程名不一樣,是兩個線程。

2021-07-26 14:11:19.429  INFO 47294 --- [pool-4-thread-2] c.e.colademo.event.handler.TestHandler   : >>>>>>>>>>>>> 0
2021-07-26 14:11:19.430  INFO 47294 --- [pool-4-thread-1] c.e.colademo.event.handler.TestHandler   : >>>>>>>>>>>>> 0

2 問題排查

爲什麼會有兩個線程同時執行呢?查看COLA源碼。

public void asyncFire(EventI event) {
    this.eventHub.getEventHandler(event.getClass()).parallelStream().map((p) -> {
        Response response = null;

        try {
            if (null != p.getExecutor()) {
                p.getExecutor().submit(() -> {
                    return p.execute(event);
                });
            } else {
                this.defaultExecutor.submit(() -> {
                    return p.execute(event);
                });
            }
        } catch (Exception var5) {
            response = this.handleException(p, response, var5);
        }

        return response;
    }).collect(Collectors.toList());
}

提交異步任務,最終都走到上面的代碼,將任務提交到線程池執行,如果沒有自定義線程池,那麼會提交到defaultExecutor 這個默認線程池中。

發現提交了兩遍,查看this對象中的內容,==發現Event對象和Handler對象都有兩個==。

圖1-線程池對象

3 問題原因

是什麼原因會造成重複對象呢?

對比之前的handler對象,這個對象唯一的不同就是使用@RefreshScope,查看註解源碼,發現使用了==這個註解的對象,都會使用代碼創建一個新的對象,並緩存起來==,debug源碼,查看緩存的對象。

圖2-Scope緩存對象

發現的確有TestHandler對象,對象爲@12349。

對比圖1中的handler對象,裏面也有一個TestHandler對象,對象也是@12349.

原來如此,因爲使用了註解@RefreshScope,這個註解會創建一個對象,這樣就會有兩個相同的對象,造成重複執行。

結論:使用註解@RefreshScope需要注意,最好把獲取配置的內容放在單獨的property對象中,不要和其他代碼混用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章