


在日常开发中,我们经常需要调用其他业务部门或者第三方的接口服务,然而网络不稳定、不可预期的因素就会导致调用失败的情况,这时候就需要根据业务情景来进行重试等措施,一般情况下我们会根据调用的结果,写while或for循环包围重试的逻辑,这会显得十分臃肿、可观性较差,这时候就需要使用FailSafe库就会让你的代码逻辑更加清晰、可维护性更高。
什么是FailSafe
Failsafe是一个轻量级、无额外依赖,用于处理故障情况的Java库,它有着简洁的API来处理日常用例,同时也有便捷的灵活性处理其他日常情景,Failsafe是通过用一个或多个弹性的polices策略包装可执行的逻辑工作的,这些策略可根据自身需要进行组合使用。
开始使用
1、首先引入failsafe依赖 https://search.maven.org/artifact/net.jodah/failsafe。2、定义重试策略,失败出现时应被处理以及重试时该执行的行为。
1//定义重试策略器RetryPolicy<Object> retryPolicy = new RetryPolicy<>() .handle(ConnectException.class) .withDelay(Duration.ofSeconds(1)) .withMaxRetries(3);
3、执行Runnable或Suppier任务
1//运行重试策略器Failsafe.with(retryPolicy).run(() -> connect());//获取结果Connection connection = Failsafe.with(retryPolicy).get(() -> connect());
4、异步执行
异步地执行一个Runnable或Suppier任务是非常简单的1//异步地运行重试策略器CompletableFuture future = Failsafe.with(retryPolicy).runAsync(() -> connect());//异步地获取重试结果CompletableFuture future = Failsafe.with(retryPolicy).getAsync(() -> connect());
5、策略器组合
可以创建并任务组合多个策略器,弹性地以不同的方式处理不同的故障情况。1CircuitBreaker<Object> circuitBreaker = new CircuitBreaker<>();Fallback<Object> fallback = Fallback.of(this::connectToBackup);// Get with circuit breaker, retries and fallbackFailsafe.with(fallback, retryPolicy, circuitBreaker).get(this::connect);
6、Failsafe执行器
多个组合策略器可以被最近使用的执行器保存下来,以供下次使用1FailsafeExecutor<Object> executor = Failsafe.with(fallback, retryPolicy, circuitBreaker);executor.run(this::connect);
policies策略
1、故障处理
policies策略定义哪些返回结果或者故障需要被处理以及如何处理,默认情况下是会处理任何抛出的异常,但我们可通过配置来处理更具体的异常或故障。
1policy .handle(ConnectException.class, SocketException.class) .handleIf(failure -> failure instanceof ConnectException);
同时可以定义条件处理结果
1policy .handleResult(null) .handleResultIf(result -> result == null);
2、策略器组合
策略器可通过任何方式组合,包括同一类型的策略器,但会以定义组合策略器相反的顺序处理执行的结果,例如:
1Failsafe.with(fallback, retryPolicy, circuitBreaker, timeout).get(supplier);Fallback(RetryPolicy(CircuitBreaker(Timeout(Supplier))))
这意味着Supplier首先会被处理,接着它的接口会被Timeout处理,然后再到circuitBreaker、retryPolicy、fallback。每个策略器都会自行决定结果是否表示失败,因此允许用不同的策略器处理不同的故障情况。
3、经典组合
一个经典的Failsafe是用多个策略器组合配置,使用Fallback作为外置的处理器,使用RetryPolicy, CircuitBreaker以及一个Timeout作为内部策略器。
1Failsafe.with(fallback, retryPolicy, circuitBreaker, timeout)
也就是说取决于策略器如何被使用、不同的组合可处理不同情景的故障。
4、重试策略器重试策略表是用来定义当发生重试时应执行哪些行为。
4.1、尝试次数默认情况下重试策略器最大尝试次数为3次,当然我们可自定义最大尝试次数
1retryPolicy.withMaxAttempts(3);
或者我们也可以配置最大重试次
1retryPolicy.withMaxRetries(2);
4.2、延迟配置
默认情况下,重试策略器在每次尝试中是没有设置延迟的,我们可自定义一个固定延迟1retryPolicy.withDelay(Duration.ofSeconds(1));
或者配置一个指数降低的延迟
1retryPolicy.withBackoff(1, 30, ChronoUnit.SECONDS);
随机的延迟
1retryPolicy.withDelay(1, 10, ChronoUnit.SECONDS);
也可以基于执行结果或故障情况来计算延迟。
4.3、抖动配置 我们可以为每个重试配置一个抖动因子1retryPolicy.withJitter(.1);
或者是基于时间配置抖动
1retryPolicy.withJitter(Duration.ofMillis(100));
在重试即将结束前,可以为每个执行设置一个最大持续时间
1retryPolicy.withMaxDuration(Duration.ofMinutes(5));
若需要取消或者中断执行,可参考超时策略器
4.5、终止 可通过配置具体的结果、故障或条件来终止重试1retryPolicy .abortWhen(true) .abortOn(NoRouteToHostException.class) .abortIf(result -> result == true)
1retryPolicy .handle(ConnectException.class) .handleResult(null);
1retryPolicy .onFailedAttempt(e -> log.error("Connection attempt failed", e.getLastFailure())) .onRetry(e -> log.warn("Failure #{}. Retrying.", e.getAttemptCount()));
1retryPolicy.onRetriesExceeded(e -> log.warn("Failed to connect. Max retries exceeded."));
1retryPolicy.onAbort(e -> log.warn("Connection aborted due to {}.", e.getFailure()));
1Timeout<Object> timeout = Timeout.of(Duration.ofSeconds(10));
1timeout.withCancel(shouldInterrupt);
1timeout.onFailure(e -> log.error("Connection attempt timed out", e.getFailure()));
1timeout.onSuccess(e -> log.info("Execution completed on time"));
6、Fallback策略器
Fallback策略器可以为失败的执行提供可选择性的结果,犹如忽略异常并提供默认的结果
1Fallback<Object> fallback = Fallback.of(defaultResult);
1Fallback<Object> fallback = Fallback.ofException(e -> new CustomException(e.getLastFailure()));
从额外的资源中计算可选择性的结果
1Fallback<Object> fallback = Fallback.of(this::connectToBackup);
CompletionStage可以作为一个fallback提供
1Fallback<Object> fallback = Fallback.ofStage(this::connectToBackup);
对于阻塞的运算,可以将Fallback配置为异步运行
1Fallback<Object> fallback = Fallback.ofAsync(this::blockingCall);
6.1、失败处理
像FailurePolicy一样,Fallbacks可配置为仅处理某些结果或故障
1fallback
.handle(ConnectException.class)
.handleResult(null);
6.2、事件监听器
Fallback策略器支持事件监听器,并在执行尝试失败时将会发出通知
1fallback.onFailedAttempt(e -> log.error("Connection failed", e.getLastFailure()))
当fallback尝试失败时
1fallback.onFailure(e -> log.error("Failed to connect to backup", e.getFailure()));
或者当执行或fallback尝试成功时:
1fallback.onSuccess(e -> log.info("Connection established"));
7、Circuit Breaker策略器
Circuit Breaker允许创建通过临时性禁用执行来达到快速失败的系统,以防止系统过载的出现,这里提供两种类型的circuit breaker策略器: 基于计数以及基于时间的方式,基于计数的circuit breaker策略器是通过追踪最近的结果达到一定的限制来进行操作的,基于时间的circuit breaker策略器是通过追踪一段时间内任何数量的执行结果来操作的。 直接创建一个circuit breaker1CircuitBreaker<Object> breaker = new CircuitBreaker<>() .handle(ConnectException.class) .withFailureThreshold(3, 10) .withSuccessThreshold(5) .withDelay(Duration.ofMinutes(1));
7.1、它是如何工作的?
当最近执行的故障结果超过配置的阈值时, Circuit Breaker将会被打开以及进一步对后续的请求以CircuitBreakerOpenException的方式返回结果,一段时间延迟后,breaker将会尝试处于半开状态、尝试接收一定的请求,并根据请求的结果决定breaker接下来是继续打开还是关闭,如果尝试的执行达到成功的法制,breaker将再次关闭并且执行将会被正常处理,否则就会重新打开。 7.2、配置Circuit Breaker可以灵活地配置表明什么时候它应该被关闭、被打开或者半开状态。
打开状态:可以将基于计数的breaker配置成在连续多次执行失败时打开
1breaker.withFailureThreshold(5);
1breaker.withFailureThreshold(3, 5);
1breaker.withFailureThreshold(3, Duration.ofMinutes(1));
1breaker.withFailureThreshold(3, 5, Duration.ofMinutes(1));
1breaker.withFailureRateThreshold(20, 5, Duration.ofMinutes(1));
1breaker.withDelay(Duration.ofSeconds(30));
1breaker.withSuccessThreshold(5);
1breaker.withSuccessThreshold(3, 5);
1circuitBreaker .handle(ConnectException.class) .handleResult(null);
1circuitBreaker
.onOpen(() -> log.info("The circuit breaker was opened"))
.onClose(() -> log.info("The circuit breaker was closed"))
.onHalfOpen(() -> log.info("The circuit breaker was half-opened"));
1breaker.open();breaker.halfOpen();breaker.close();if (breaker.allowsExecution()) { try { breaker.preExecute(); doSomething(); breaker.recordSuccess(); } catch (Exception e) { breaker.recordFailure(e); }}
7.8、基于时间的方案
基于时间的breaker是以滑动窗口机制来汇总执行结果的,随着时间的推移及新结果的产生,旧结果将会被抛弃。 为了保证时间与空间上的效率,结果将会被划分为10个分片,每个分片表示配置故障周期的十分之一,当时间片不处于阈值段内,结果将会被抛弃,这个允许circuit breaker根据最近的结果进行操作,而不需要追踪每个单独的时间。7.9、性能
Failsafe内部的circuit breaker同时实现了时间与空间的效率,利用单个循环数据结构记录结果,记录执行以及计算是否达到阈值的时间复杂度为O(1)。 特性 1、定时器 默认情况下,Failsafe使用ForkJoinPool的线程池来实现异步执行,但我们也可以配置一个更详细的ScheduledExecutorService,根据业务情景自定义 Scheduler、ExecutorService使用1Failsafe.with(policy).with(scheduler).getAsync(this::connect);
1Failsafe.with(retryPolicy, circuitBreaker) .onComplete(e -> { if (e.getResult() != null) log.info("Connected to {}", e.getResult()); else if (e.getFailure() != null) log.error("Failed to create connection", e.getFailure()); }) .get(this::connect);
1Failsafe.with(retryPolicy, circuitBreaker) .onSuccess(e -> log.info("Connected to {}", e.getResult())) .get(this::connect); Failsafe.with(retryPolicy, circuitBreaker) .onFailure(e -> log.error("Failed to create connection", e.getFailure())) .get(this::connect);
1policy .onSuccess(e -> log.info("Connected to {}", e.getResult())) .onFailure(e -> log.error("Failed to create connection", e.getFailure()));
3、强类型
Failsafe是基于预期执行结果的类型API,对于各种执行策略器,结果类型可能是Object。1RetryPolicy<Object> retryPolicy = new RetryPolicy<>();
1RetryPolicy retryPolicy = new RetryPolicy() .handleResultIf(response -> response.getStatusCode == 500) .onFailedAttempt(e -> log.warn("Failed attempt: {}", e.getLastResult().getStatusCode()));
1HttpResponse response = Failsafe.with(retryPolicy) .onSuccess(e -> log.info("Success: {}", e.getResult().getStatusCode())) .get(this::sendHttpRequest);
1Failsafe.with(retryPolicy).run(ctx -> { log.debug("Connection attempt #{}", ctx.getAttemptCount()); connect();});
1int result = Failsafe.with(retryPolicy).get(ctx -> ctx.getLastResult(0) + 1);
1Future future = Failsafe.with(retryPolicy).getAsync(this::connect);future.cancel(shouldInterrupt);
5.1、处理取消
Executions的取消可配合使用ExecutionContext.isCancelled()来达到效果1while (!ctx.isCancelled()) doWork();});
1Failsafe.with(timeout).getAsync(ctx -> { while (!Thread.isInterrupted()) doBlockingWork();});
6、异步API的支持
Failsafe可通过异步返回结果的API代码交互,runAsyncExecution, getAsyncExecution及getStageAsyncExecution方法提供异步执行的引用,用于从内部的异步回调中定期的重试或完成执行。1Failsafe.with(retryPolicy) .getAsyncExecution(execution -> service.connect().whenComplete((result, failure) -> { if (execution.complete(result, failure)) log.info("Connected"); else if (!execution.retry()) log.error("Connection attempts failed", failure); }));
7、CompletionStage的支持
Failsafe在处理故障 配置中可接受一个CompletionStage参数且返回新的CompletableFuture1Failsafe.with(retryPolicy) .getStageAsync(this::connectAsync) .thenApplyAsync(value -> value + "bar") .thenAccept(System.out::println));
1Execution execution = new Execution(retryPolicy);while (!execution.isComplete()) { try { doSomething(); execution.complete(); } catch (ConnectException e) { execution.recordFailure(e); }}
1Execution execution = new Execution(retryPolicy);// On failureif (execution.canRetryOn(someFailure)) service.scheduleRetry(execution.getWaitTime().toNanos(), TimeUnit.MILLISECONDS);
最后
以上就是昏睡鸵鸟最近收集整理的关于ajax timeout如何使用_Failsafe中文使用指南的全部内容,更多相关ajax内容请搜索靠谱客的其他文章。
发表评论 取消回复