最近RP編程很火,筆者也藉機腦補了一下,藉此跟以前工做時遇到的一個問題發生了關聯···java
The Four Reactive Principlesreact
其中即是第二點Resilient(彈性的、有復原力的),當看到這個原則時,馬上想起來不久前一個用戶遇到的一個BUG便跟這個Resilient有關,並致使用戶必須重啓服務才能解決,究竟是啥有趣的BUG呢,請容筆者細細道來。apache
某日,一業務開發同窗(客戶啊)郵件過來直接就問:個人服務發生OOM後通過一次FGC恢復了,可是個人I/O Rector has been shutdown以後就一直無法恢復了是怎麼回事呀?是否是大家又搞出來一個BUG呀?收到郵件後仔細看了看,發現報錯是從一個RxCachedThreadScheduler-36線程拋出來的信息,大意就是說沒法處理請求了(異步請求),啥?RxJava?咱們還沒用到這玩意兒呢!看了看異常棧以後才頓然發現,其實跟這玩意不要緊(注:這個是tomcat自身的一個守護線程,採用觀察者模式,一旦IO thread 發生crush後會記錄日誌通知用戶,此處省略一萬字···)編程
仔細看了看代碼以後發現,咱們在處理async http request的時候用了apache async client包,正是這個包在處理代碼時一旦進入STOPED狀態後,將沒法再次從新進入ACTIVE狀態,除非重啓進程或者從新new一個client對象,這就讓筆者很是糾結了,具體可參見:httpasyncclient-4.1.2.jar 包中CloseableHttpAsyncClientBase.java這個類,縱觀此類,2處可致使該client進入STOPED狀態:tomcat
第一處:異步
this.reactorThread = threadFactory.newTread(new Runnable() { @Override public void run() { try { final IOEventDispatch ioEventDispatch = new InternalIODispatch(handler); connmgr.execute(ioEventDispatch); } catch (final Exception ex) { log.error("I/O reactor terminated abnormally", ex); } finally { status.set(Status.STOPED) }
第二處:async
@Override public void close() { if (this.status.compareAndSet(Status.ACTIVE, Status.STOPED)) { if (this.reactorThread != null) { try { this.connmgr.shutdown(); } catch (IOException ex) { this.log.error("I/O error shutting down connection manager", ex); } try { this.reactorThread.join(); } catch (final InterruptedException ex) { Thread.currentThread().interrupt(); } } } }
OK,看到這2個地方,應該你們都明白了,第一個地方紅色代碼處,一旦發生了OOM,new操做會失敗拋異常並致使Stauts爲STOPED,詭異的是沒有找到任何代碼再將此狀態置回爲ACTIVE,那麼致使的結果就是這個reactorThread一旦catch住了一個異常(爲啥要Catch Exception,尼瑪···)這個async client就直接沒法再被使用了,更加詭吊的是這個做者在start()方法裏寫的居然是:ide
if (this.status.compareAndSet(Status.INACTIVE, Status.ACTIVE)) {this
startThread ...spa
}
這是徹底不給STOPED後再start起來的機會呀!俺們在外面封裝了該client,遇到異常咱們吃不到,啓動也啓動不了,這後路斷的夠絕!
看來是時候給這位大佬提點意見了,不爲別的,只爲Resilient ... ...