Nodejs中request出现ESOCKETTIMEDOUT解决方案

来源:http://www.chinese-glasses.com 作者:Web前端 人气:80 发布时间:2020-03-24
摘要:做需求的时候,使用Nodejs的request批量请求某一个接口,由于接口超时,出现ESOCKETTIMEDOUT,程序中断。 1)FeignClient重试机制分析  1、加上 try...catch 之后,程序就不会因为某一条 request

做需求的时候,使用Nodejs的request批量请求某一个接口,由于接口超时,出现 ESOCKETTIMEDOUT,程序中断。

1)FeignClient重试机制分析 

1、加上 try...catch 之后,程序就不会因为某一条 request 报错而中断。

《SpringCloud | Feign如何整合Ribbon进行负载均衡的?》,所以下面就跳过整合部分,直接分析负载均衡模块。

try{ //这里是你request请求的代码}catch(e){ //这里需要用一些措施记录下失败的数据 //1.将错误请求输出到某一个日志文件中 //2.将错误请求保存到某个数组中,下面通过循环不断重试直至成功 console.log(e);}

执行顺序:

说明:

上述代码是Ribbon判断是否重试的实现,根据我们配置的变量次数,进行判断,有异常则进入异常处理。 

时间: 2019-11-02阅读: 156标签: 异常处理

10bet 1

2、在 catch 中将有问题的请求记录下来,方便后面重试。

1)FeignClient 重试机制分析:

为了让程序遇到ESOCKETTIMEDOUT 之后能够继续执行下去,需要对 request 部分加上 try...catch,再catch中记录这条失败请求的信息,后面不断重试。

n(请求总次数)=feign(默认5次) * (MaxAutoRetries+1) * (MaxAutoRetriesNextServer+1)

这里从字面意思可以看出: 

10bet,3)FeignClient 和 Ribbon重试区别与联系:

上述代码是对请求类型进行区分,哪些重试,哪些不重试。 

区别就在于第二个参数,来看一下第二个参数具体哪里用到了,继续跟进代码如下:

整体的重试机制就是将 LoadBalancerCommand 类中 retryPolicy 的重试实现逻辑,传入RxJava Observable对象的o.retry()方法,该方法接收的参数的就是一个Function:

@OverridepublicObjectinvoke(Object[] argv)throwsThrowable {//生成处理请求模板RequestTemplate template = buildTemplateFromArgs.create(argv);//获取重试配置类Retryer retryer =this.retryer.clone();while(true) {try{returnexecuteAndDecode(template);      }catch(RetryableException e) {//在异常里执行是否重试方法retryer.continueOrPropagate(e);if(logLevel != Logger.Level.NONE) {          logger.logRetry(metadata.configKey(), logLevel);        }continue;      }    }  }

判断是否重试的算法如下:

默认的请求次数为5次,构造方法如下:

publicvoidcontinueOrPropagate(RetryableException e) {//重试次数大于最大请求次数,抛出异常if(attempt++ >= maxAttempts) {throwe;      }longinterval;if(e.retryAfter() !=null) {        interval = e.retryAfter().getTime() - currentTimeMillis();if(interval > maxPeriod) {          interval = maxPeriod;        }if(interval <0) {return;        }      }else{        interval = nextMaxInterval();      }try{        Thread.sleep(interval);      }catch(InterruptedException ignored) {        Thread.currentThread().interrupt();      }      sleptForMillis += interval;    }

SpringCloud | FeignClient和Ribbon重试机制区别与联系

上述代码典型的RxJava风格。 

/** * @authorzhangshukang */@ConfigurationpublicclassFeignConfig{@BeanRetryer feignRetryer() {returnnewRetryer() {@Override//在这里重写 continueOrPropagate算法,可自定义处理方式。这里直接抛出异常,相当于不重试。publicvoidcontinueOrPropagate(RetryableException e) {throwe;            }@OverridepublicRetryerclone() {returnthis;            }        };    }}

现在在回过头看这两行代码:

+1是代表ribbon本身默认的请求。

publicObservablesubmit(finalServerOperation operation) {finalExecutionInfoContext context =newExecutionInfoContext();if(listenerInvoker !=null) {try{            listenerInvoker.onExecutionStart();        }catch(AbortExecutionException e) {returnObservable.error(e);        }    }//这两个变量,上面已经提到了,重试机制的关键finalintmaxRetrysSame = retryHandler.getMaxRetriesOnSameServer();finalintmaxRetrysNext = retryHandler.getMaxRetriesOnNextServer();// 利用RxJava生成一个Observable用于后面的回调Observable o =//选择具体的server进行调用(server ==null? selectServer() : Observable.just(server))            .concatMap(newFunc1>() {@Override// Called for each server being selectedpublicObservablecall(Server server) {                    context.setServer(server);//获取这个server调用监控记录,用于各种统计和LoadBalanceRule的筛选server处理finalServerStats stats = loadBalancerContext.getServerStats(server);//获取本次server调用的回调入口,用于重试同一实例的重试回调Observable o = Observable                            .just(server)                            .concatMap(newFunc1>() {@OverridepublicObservablecall(finalServer server) {                                    context.incAttemptCount();                                    loadBalancerContext.noteOpenConnection(stats);if(listenerInvoker !=null) {try{                                            listenerInvoker.onStartWithServer(context.toExecutionInfo());                                        }catch(AbortExecutionException e) {returnObservable.error(e);                                        }                                    }finalStopwatch tracer = loadBalancerContext.getExecuteTracer().start();                                ......省略部分代码                                }                            });//设置针对同一实例的重试回调if(maxRetrysSame >0)                        o = o.retry(retryPolicy(maxRetrysSame,true));returno;                }            });//设置重试下一个实例的回调    if(maxRetrysNext >0&& server ==null)        o = o.retry(retryPolicy(maxRetrysNext,false));//异常回调returno.onErrorResumeNext(newFunc1>() {@OverridepublicObservablecall(Throwable e) {if(context.getAttemptCount() >0) {if(maxRetrysNext >0&& context.getServerAttemptCount() == (maxRetrysNext +1)) {                    e =newClientException(ClientException.ErrorType.NUMBEROF_RETRIES_NEXTSERVER_EXCEEDED,"Number of retries on next server exceeded max "+ maxRetrysNext                            +" retries, while making a call for: "+ context.getServer(), e);                }elseif(maxRetrysSame >0&& context.getAttemptCount() == (maxRetrysSame +1)) {                    e =newClientException(ClientException.ErrorType.NUMBEROF_RETRIES_EXEEDED,"Number of retries exceeded max "+ maxRetrysSame                            +" retries, while making a call for: "+ context.getServer(), e);                }            }if(listenerInvoker !=null) {                listenerInvoker.onExecutionFailed(e, context.toFinalExecutionInfo());            }returnObservable.error(e);        }    });}

publicTexecuteWithLoadBalancer(finalS request,finalIClientConfig requestConfig)throwsClientException {//获取重试机制配置:RequestSpecificRetryHandler,继续跟进该方法...RequestSpecificRetryHandler handler = getRequestSpecificRetryHandler(request, requestConfig);//这里很关键,很明显采用了命令模式,ribbon负载均衡的配置在这里传给LoadBalancerCommand类LoadBalancerCommand command = LoadBalancerCommand.builder()                .withLoadBalancerContext(this)                .withRetryHandler(handler)                .withLoadBalancerURI(request.getUri())                .build();try{returncommand.submit(newServerOperation() {@OverridepublicObservablecall(Server server) {                        URI finalUri = reconstructURIWithServer(server, request.getUri());                        S requestForServer = (S) request.replaceUri(finalUri);try{returnObservable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));                        }catch(Exception e) {returnObservable.error(e);                        }                    }                })                .toBlocking()                .single();        }catch(Exception e) {            Throwable t = e.getCause();if(tinstanceofClientException) {throw(ClientException) t;            }else{thrownewClientException(e);            }        }    }

这里声明一点,关于feignClient如何整合ribbon负载均衡的,之前的博客已经有完整的分析: 

publicbooleanisRetriableException(Throwable e,booleansameServer) {//如果手动配置了所有请求都重试,或者get请求时,这里开启重试。if(this.okToRetryOnAllErrors) {returntrue;        }elseif(einstanceofClientException) {            ClientException ce = (ClientException)e;returnce.getErrorType() == ErrorType.SERVER_THROTTLED?!sameServer:false;        }else{returnthis.okToRetryOnConnectErrors &&this.isConnectionException(e);        }    }

2)再执行上面一行代码,获取执行单个服务的重试逻辑实现,最后再执行具体的业务逻辑。

retrySameServer:重试相同实例,对应MaxAutoRetries 

本文由10bet发布于Web前端,转载请注明出处:Nodejs中request出现ESOCKETTIMEDOUT解决方案

关键词:

上一篇:没有了

下一篇:【转】技术人员在大公司能学到什么

最火资讯