Attempt is a lightweight component provides declarative retry support for applications, not only but a polling strategy. With Attempt, you can easily poll for something with retry functionality. Non-spring and lightweight applications are friendly for a fewer dependencies.

Overview

中文文档

Introduction

Attempt is a lightweight component provides declarative retry support for applications, not only but a polling strategy. With Attempt, you can easily poll for something with retry functionality. Non-spring and lightweight applications are friendly for a fewer dependencies.

Quick Start

This section provides a quick introduction to getting started with Attempt. It includes a static method call example, and an object call example.

maven dependency

<dependency>
    <groupId>io.github.icefrozen</groupId>
    <artifactId>Attempt</artifactId>
    <version>0.1.0</version>
</dependency>

An Object Call example

  • First, define the base class
public class User {
    private int id;
    private String name;
    private Integer age;
    // the set get method and constructor are ignored
}

public class UserService {
    public User queryUser (int id) {
        return new User(id, "test" + id, 1);
    }
}
  • Second, build Attempt
UserService userService = new UserService();
// Building a Retry Policy
AttemptBuilder.Retry<UserService> userRetry = new AttemptBuilder.Retry<UserService>(userService);
// Generate the retry proxy Object
UserService userServiceAttempt = userRetry.build();
// invoke the method and get the result
User user = userServiceAttempt.queryUser(1);

Since there are no exceptions in queryUser, this code returns immediately, no different from a direct call.

  • Retry if an exception occurs.

Now we throw an RuntimeException in the queryUser method and call it again.

public class UserService {
    public int count = 0;
    public User queryUser (int id) {
        count ++;
        throw new RuntimeException("queryUser error");
    }

    public static void main(String[] args) {
        UserService userService = new UserService();
        AttemptBuilder.Retry<UserService> userRetry = new AttemptBuilder.Retry<UserService>(userService);
        UserService userServiceAttempt = userRetry.build();
        try {
            User user = userServiceAttempt.queryUser(1);
        } catch (RuntimeException e) {
            System.out.println(e.getMessage());     // queryUser error
            // original object here
            System.out.println(userService.count);      // The original method has been called three times
        }
    }
}

As we see, when we execute the userServiceAttempt's queryUser method, the userServiceAttempt will be automatically retried three times. After that, the exception has been thrown.

AttemptBuilder can make the method in a proxy object to retries when the exception has been thrown automatically?

How do we assign retry to static methods?

a static method call example

public class UserService {
    public int count = 0;
    public static int staticCount = 0;
    public User queryUser (int id) {
        count ++;
        throw new RuntimeException("queryUser error");
    }

    public static User queryUserStatic (int id) {
        staticCount ++;
        throw new RuntimeException("queryUser error");
    }

    public static void main(String[] args) {
        UserService userService = new UserService();
        try {
            AttemptBuilder.retry(() -> UserService.queryUserStatic(1)).exec(); 
        } catch (RuntimeException e) {
           // ... staticCount > 3 then throw exception
        }
    }
}

Polling Strategy

Suppose there is such a case, you upload a task, the server does not support callback or message queue to notify you whether the task is finish, then you need a polling strategy to know the status of the task. For stability, you need to meet the following characteristics:

  • if the process of querying the progress fails, then in order for the task to continue, it must be retried, for example, a call timeout occurs.
  • if the call fails after retries 3 times (the maximum number of retries is tentatively set to 3 times), then report an error directly and return failure.
  • if the network resumes trial operation at this stage, then clear the history three times and continue to poll the call.

As shown in the figure above, Attempt sets the polling strategy. If an exception occurs during the polling process, it will enter retry stage. In retry stage, the number of retries will be accumulated. If retry is successful, it will continue to enter the polling phase, and the number of retries in retry phase will be cleared.

example:

public class TaskService {
    public List<Integer> history = new ArrayList<>();
    public Integer nowProgress = 0;             // process
    public Integer queryProgressStep = 0;      // queryProgress invoke time
    //  Progress step need to throw exception
    public List<Integer> errorThrowOrder = new ArrayList<>();

    public Integer queryProgress () {
        history.add(nowProgress);
        queryProgressStep++;
        if(errorThrowOrder.contains(queryProgressStep)) {
            throw new RuntimeException("timeout exception:" + nowProgress);
        }
        SecurityThreadWaitSleeper.sleep(500);
        nowProgress +=10;

        return nowProgress;
    }

    public static void main(String[] args) {
        Integer retryCount = 3;
        TaskService taskService = new TaskService();
        // 2 3 3 count will throw RuntimeException
        taskService.errorThrowOrder = Stream.of(2, 3, 4).collect(Collectors.toList());
        // poll builder
        AttemptBuilder.Polling<TaskService> taskServicePollBuilder = new AttemptBuilder.Polling<>(taskService);
        // set end point
        TaskService taskServicePoll = taskServicePollBuilder.endPoint(context -> {
            // get last result
            AttemptResult result = context.getLastResult();
            if (result.isSuccess()) {
                Integer progress = result.getRetValue(Integer.class);
                return progress == 100;      //  progress < 100 poll continue
            }
            return false;
        })
         .maxPollCount(100)      // max poll times
         .registerExceptionRetryTime(RuntimeException.class, retryCount)   // the exception that should entry retry stage
         .build();

        try {
            Integer integer = taskServicePoll.queryProgress();
        }catch (RuntimeException e) {
            System.out.println("queryProgressStep:" + taskService.queryProgressStep); //
            System.out.println("history:" + taskService.history);//
        }
    }

}
  • It can be seen that when we set (2, 3, 4) calls, an exception will be thrown, and the result will be obtained after encountering the exception RuntimeException.class, and retrying 3 times.
    queryProgressStep:4
    history:[0, 10, 10, 10]
    

Called 4 times, progress is in 10. That is to say, when the number of calls is 2, 3, and 4 three consecutive calls, an exception has been thrown.

  • When we set an exception RuntimeException.class, retry 4 times. But we said that the exception will be thrown when 2, 3, and 4 are called three times in a row, so the call returns 100 successfully.
    // ......
    Integer retryCount = 4;
    // ......
  • When we set the exception sequence to 2, 3, 5, 6, 7, since 23 is not continuous, it will continue to be called after retrying in stage 23, and it will not end until it encounters 567 three consecutive exceptions.
      Integer retryCount = 3;
      taskService.errorThrowOrder = Stream.of(2, 3, 5,6,7).collect(Collectors.toList());
    返回结果
    queryProgressStep:7
    queryProgressStep:[0, 10, 10, 10, 20, 20, 20]
    

Performance VS SpringRetry

code here

Benchmark Mode Cnt Score Error Units
AttemptVsSpringRetry.testAttempt avgt 10 165.921 ± 26.558 ns/op
AttemptVsSpringRetry.testGuavaRetry avgt 10 909259.747 ± 323278.426 ns/op
AttemptVsSpringRetry.testSpringRetry avgt 10 50681.819 ± 2848.606 ns/op

Author

Advanced

more:Wiki

You might also like...

Unirest in Java: Simplified, lightweight HTTP client library.

Unirest for Java Install With Maven: !-- Pull in as a traditional dependency -- dependency groupIdcom.konghq/groupId artifactIdunire

Jan 5, 2023

Fast_Responder is a service that lets you quickly create an Http request responder

Fast_Responder is a service that lets you quickly create an Http request responder

Fast_Responder is a service that lets you quickly create an Http request responder. The transponder can receive any request path configured and determine the request parameters according to your configuration to return different results. In addition to processing requests, the transponder can also make Http requests to any request address based on the latency, request headers, and parameters you configure. In essence, fast_responder is a dynamic mock service.

Jan 26, 2022

Client-side response routing for Spring

Client-side response routing for Spring

Riptide: A next generation HTTP client Riptide noun, /ˈrɪp.taɪd/: strong flow of water away from the shore Riptide is a library that implements client

Jan 3, 2023

Share the chat messages across Minecraft Servers via HTTP backend powered by Spring Boot, this is the backend part of the project.

InterconnectedChat-Backend Share the chat messages across Minecraft Servers via HTTP backend powered by Spring Boot, this is the backend part of the p

Oct 6, 2021

Konas Client de-obfuscated and manually remaped by Gopro336, Perry, and other based people

Konas-Deobf-Remap This project doesent really have a purpose anymore now that the real source code has leaked (this is a higher version tho) Deobfusca

Dec 13, 2022

Asynchronous Http and WebSocket Client library for Java

Async Http Client Follow @AsyncHttpClient on Twitter. The AsyncHttpClient (AHC) library allows Java applications to easily execute HTTP requests and a

Jan 8, 2023

Square’s meticulous HTTP client for the JVM, Android, and GraalVM.

OkHttp See the project website for documentation and APIs. HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP

Jan 5, 2023

A Java event based WebSocket and HTTP server

Webbit - A Java event based WebSocket and HTTP server Getting it Prebuilt JARs are available from the central Maven repository or the Sonatype Maven r

Jan 3, 2023

ssh, scp and sftp for java

sshj - SSHv2 library for Java To get started, have a look at one of the examples. Hopefully you will find the API pleasant to work with :) Getting SSH

Jan 4, 2023
Owner
Jason Lee
Jason Lee
Tiny, easily embeddable HTTP server in Java.

NanoHTTPD – a tiny web server in Java NanoHTTPD is a light-weight HTTP server designed for embedding in other applications, released under a Modified

NanoHttpd 6.5k Jan 5, 2023
This client is still in development - Xena is a 1.12.2 Minecraft Utility Mod designed for Anarchy servers such as 2b2t/9b9t/5b5t etc, Devs are not responsible for improper usage.

Xena-client This client is still in development - Xena is a 1.12.2 Minecraft Utility Mod designed for Anarchy servers such as 2b2t/9b9t/5b5t etc, Devs

PreparedSystem_32 4 Oct 18, 2021
Simple Java library that can export all of your Spring endpoints into a Postman Collection

Postman Exporter for Spring This project is a simple Java library that can export all of your Spring endpoints into a Postman Collection json, which y

Lucas Sampaio Dias 30 Sep 6, 2022
Allows you to duplicate items via the server kicking you. (Credits to TheTroll2001)

CloseConnection Dupe (1.12.2-1.17.1) Allows you to duplicate items via the server kicking you. (Credits to TheTroll2001) Usage Type .dupe <method> <pa

null 20 Nov 15, 2022
http-kit is a minimalist, event-driven, high-performance Clojure HTTP server/client library with WebSocket and asynchronous support

HTTP Kit A simple, high-performance event-driven HTTP client+server for Clojure CHANGELOG | API | current Break Version: [http-kit "2.5.3"] ; Publish

HTTP Client/Server for Clojure 2.3k Dec 31, 2022
Ribbon is a Inter Process Communication (remote procedure calls) library with built in software load balancers. The primary usage model involves REST calls with various serialization scheme support.

Ribbon Ribbon is a client side IPC library that is battle-tested in cloud. It provides the following features Load balancing Fault tolerance Multiple

Netflix, Inc. 4.4k Jan 1, 2023
This tool can read the QR code from the Remote Admin menu and copy the ID of the User to the Clipboard.

SCP-SL-QR-Reader Tool for easy copying This tool can read the QR code from the Remote Admin menu and copy the ID of the User to the Clipboard. Detecta

null 6 Aug 14, 2021
A high-level and lightweight HTTP client framework for Java. it makes sending HTTP requests in Java easier.

A high-level and lightweight HTTP client framework for Java. it makes sending HTTP requests in Java easier.

dromara 1.2k Jan 8, 2023
⚗️ Lightweight HTTP extensions for Java 11

Methanol A lightweight library that complements java.net.http for a better HTTP experience. Overview Methanol provides useful lightweight HTTP extensi

Moataz Abdelnasser 175 Dec 17, 2022
Unirest in Java: Simplified, lightweight HTTP client library.

Unirest for Java Install With Maven: <!-- Pull in as a traditional dependency --> <dependency> <groupId>com.konghq</groupId> <artifactId>unire

Kong 2.4k Jan 5, 2023