最近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 ... ...