In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-12 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
This article is to share with you about how to use Guava Retrying, the editor thinks it is very practical, so I share it with you to learn. I hope you can get something after reading this article.
Retry usage scenario in many business scenarios, in order to eliminate various unstable factors in the system, as well as logical errors, and the maximum probability to ensure the desired results, the retry mechanism is essential. Especially when invoking remote services, in high concurrency scenarios, we may not get the desired results or get no response at all because of server response delay or network reasons. At this point, an elegant retry invocation mechanism allows us to have a higher probability of getting the expected response. SequenceDiagram Client- > > Server: {"msg": "hello,server"} Note right of Server: busying. Client- > > Server: {"msg": "hello,server"}
Server-- > > Client: {"Exception": "500"} Note right of Server: busying. Loop ServerBlock Server-- > Server: Too busy to deal with so many requests... EndClient- > > Server: {"msg": "hello,server"} activate ServerServer-- > > Client: {"msg": "hello,client"} deactivate Server
Usually, we retry through scheduled tasks. For example, if an operation fails, record it, and when the scheduled task starts again, put the data into the method of the scheduled task and run it again. In the end, until you get the desired results. Whether it is a retry mechanism based on scheduled tasks or a simple retry written by ourselves, the disadvantage is that the retry mechanism is too simple and not elegant to implement. How to gracefully design and retry to achieve a complete retry implementation, it is necessary to solve the following problems:
Under what conditions retry under what conditions stop retry wait how long wait for request time limit how to end and how to monitor the entire retry process
And, for better encapsulation, the implementation of retry is generally divided into two steps:
Construct a retry using the factory pattern to execute the retry method and get the results
A complete retry process can be simply indicated as: graph LR A ((Start))-> | build | B (Retryer) B-> C {need call?} C-> | continue | D [call] D-> Z [call count++] Z-> C-> | finished | E [result] E-> F ((success)) E-> G (failed))
The basic usage of guava-retrying guava-retrying is based on the retry mechanism of Google's core class library guava, which can be said to be a retry weapon. Let's take a quick look at its usage. 1.Maven configuration com.github.rholder guava-retrying 2.0.0
It is important to note that this version relies on version 27.0.1 of guava. If you have a few lower versions of guava in your project, it will be fine, but much lower will not be compatible. At this point you need to upgrade the guava version of your project, or just get rid of your own guava dependencies and use the guava dependencies passed by guava-retrying. two。 Implement Callable Callable callable = new Callable () {public Boolean call () throws Exception {return true; / / do something useful here}}
In the call method of Callable is your own actual business call.
Constructing Retryer through RetryerBuilder
Retryer retryer = RetryerBuilder.newBuilder () .retryIfResult (Predicates.isNull ()) .retryIfExceptionOfType (IOException.class) .retryIfRuntimeException () .withStopStrategy (StopStrategies.stopAfterAttempt (3)) .build ()
Use the retry to execute your business
Retryer.call (callable)
Here is the complete reference implementation. Public Boolean test () throws Exception {/ / define retry mechanism Retryer retryer = RetryerBuilder.newBuilder () / / retryIf retry condition .retryIfException () .retryIfRuntimeException () .retryIfExceptionOfType (Exception.class). RetryIfException (Predicates.equalTo (new Exception () .retryIfResult (Predicates.equalTo (false))
/ / wait policy: interval 1s. WithWaitStrategy (WaitStrategies.fixedWait (1, TimeUnit.SECONDS)) / / stop policy: try requests 6 times. WithStopStrategy (StopStrategies.stopAfterAttempt (6)) / / time limit: a request must not exceed 2 seconds, similar to: TimeLimiter timeLimiter = new SimpleTimeLimiter (); .withAttemptTimeLimiter (AttemptTimeLimiters.fixedTimeLimit (2, TimeUnit.SECONDS)) .build () / / define request implementation Callable callable = new Callable () {int times= 1; @ Override public Boolean call () throws Exception {log.info ("call times= {}", times); times++; if (times= = 2) {throw new NullPointerException ();} else if (times= = 3) {throw new Exception () } else if (times = = 4) {throw new RuntimeException ();} else if (times = = 5) {return false;} else {return true;}; / / invoke the request using the retry
Return retryer.call (callable);}
The core of guava-retrying implementation principle guava-retrying is Attempt class, Retryer class and some Strategy (policy) related classes.
Attempt
Attempt is both a retry request (call) and the result of the request, and records the number of times the current request, whether it contains an exception, and the return value of the request. / * *
An attempt of a call, which resulted either in a result returned by the call
Or in a Throwable thrown by the call.
@ param The type returned by the wrapped callable.
@ author JB * / public interface Attempt
Retryer
Retryer is constructed through the factory class RetryerBuilder. RetryerBuilder is responsible for assigning the defined retry policy to the Retryer object. Each of these retry strategies is used when Retryer executes the call method. Let's take a look at the concrete implementation of Retryer's call method. / * Executes the given callable. If the rejection predicate * accepts the attempt, the stop strategy is used to decide if a new attempt * must be made. Then the wait strategy is used to decide how much time to sleep * and a new attempt is made. * * @ param callable the callable task to be executed * @ return the computed result of the given callable * @ throws ExecutionException if the given callable throws an exception, and the * rejection predicate considers the attempt as successful. The original exception * is wrapped into an ExecutionException. * @ throws RetryException if all the attempts failed before the stop strategy decided * to abort, or the thread was interrupted. Note that if the thread is interrupted, * this exception is thrown and the thread's interrupt status is set. * / public V call (Callable callable) throws ExecutionException, RetryException {long startTime = System.nanoTime (); / / description: cycle according to attemptNumber-that is, how many times to retry for (int attemptNumber = 1;; attemptNumber++) {/ / description: enter the method without waiting, immediately execute Attempt attempt; try {/ / description: performing specific business in callable / / attemptTimeLimiter limits the number of times you can wait for each attempt V result = attemptTimeLimiter.call (callable) / / construct a new attempt attempt = new ResultAttempt (result, attemptNumber, TimeUnit.NANOSECONDS.toMillis (System.nanoTime ()-startTime));} catch (Throwable t) {attempt = new ExceptionAttempt (t, attemptNumber, TimeUnit.NANOSECONDS.toMillis (System.nanoTime ()-startTime));}
/ / description: traverse the custom listener for (RetryListener listener: listeners) {listener.onRetry (attempt);} / description: determine whether the retry condition is met to decide whether to continue waiting and retry if (! rejectionPredicate.apply (attempt)) {return attempt.get () } / / description: the stop policy is satisfied at this time, because the desired result has not been obtained, so an exception if (stopStrategy.shouldStop (attempt)) {throw new RetryException (attemptNumber, attempt);} else {/ / description: execute the default stop policy-thread hibernation long sleepTime = waitStrategy.computeSleepTime (attempt) Try {/ / description: you can also execute the defined stop policy blockStrategy.block (sleepTime);} catch (InterruptedException e) {Thread.currentThread (). Interrupt (); throw new RetryException (attemptNumber, attempt);}
}
The Retryer execution process is as follows. Graph TB
Sq [Retryer]-- > ci ((call)) subgraph Retrying rb > RetryerBuilder]-- build retryerwith strategies-- > ro di {Retryer:using callable whith strategies execute call...} -. > ro (
.retryIf...
.withWaitStrategy
.withStopStrategy
.withAttemptTimeLimiter
.withBlockStrategy
.withRetryListene) di== > ro2 (Attempt: get the result) end classDef green fill:#9f6,stroke:#333,stroke-width:2px; classDef orange fill:#f96,stroke:#333,stroke-width:4px; class sq,e green class di orange
The advanced usage of guava-retrying is based on the implementation principle of guava-retrying, and we can determine our retry strategy according to the actual business. Let's take the general system business of data synchronization as an example to customize the retry policy. The following implementation is based on the Spring Boot 2.1.2.RELEASE version. And use Lombok to simplify Bean. Org.projectlombok lombok true
Business description when the goods are created, you need to set the price of the goods separately. Because the two operations are performed by two people, there will be the following problem, that is, the product has not been created, but the price data has been established. In this case, the price data needs to wait for the product to be created normally and then continue to complete the synchronization. We create the product through a http request and modify the price of the product through a timer. When the commodity does not exist, or the quantity of the commodity is less than 1, the price of the commodity cannot be set. You need to wait for the product to be successfully created and the quantity is greater than 0 before the price of the product can be set successfully. Realization process
Custom retry blocking policy
The default blocking strategy is thread hibernation, which is implemented using spin locks and does not block threads. Package net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.strategy
Import com.github.rholder.retry.BlockStrategy; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j
Import java.time.Duration; import java.time.LocalDateTime
/ * *
Implementation of spin lock that does not respond to thread interrupts * / @ Slf4j @ NoArgsConstructor public class SpinBlockStrategy implements BlockStrategy {
@ Override public void block (long sleepTime) throws InterruptedException {
LocalDateTime startTime = LocalDateTime.now (); long start = System.currentTimeMillis (); long end = start; log.info ("[SpinBlockStrategy]... begin wait."); while (end-start)
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.