美文网首页
异步调用与重试

异步调用与重试

作者: zxbyh | 来源:发表于2023-03-04 20:38 被阅读0次

在业务场景经常会有类似这样的情况,比如说用户交易成功后,需要调用第三方接口给用户发放其他权益. 这个调用不能做成同步的,否则如果第三方系统出问题就会堵塞我们正常的业务. 其实可以用如下思路来解决.

异步调用, 如果失败了再重试n次, 代码如下:

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CompletableFuture;

public class AsyncScheduleCompletableFutureTest {
    private static volatile Integer askCount = 0;

    private static Boolean doTask(){
        return (int)(Math.random() * 100)>80;
    }

    private static String asyncDo(){
        CompletableFuture.supplyAsync(() -> {
            return doTask();
        }).thenAccept(r-> {
            askCount++;
            System.out.println("异步任务首次调用执行返回,"+r+",调用次数"+askCount);
            if(r){
                System.out.println("异步任务调用成功!");
                return;
            }
            System.out.println("异步任务调用失败,进入定时调用");
            scheduleDo();

        });
        return "已经将任务放到异步,主函数返回!";
    }

    public static void scheduleDo(){
        (new Timer()).schedule(
            new TimerTask(){
                public void run(){
                    System.out.println("异步任务进入延迟调用执行!");
                    CompletableFuture.supplyAsync(() -> {
                        return doTask();
                    }).thenAccept(r-> {
                        askCount++;
                        System.out.println("异步任务延迟调用执行返回,"+r+",调用次数"+askCount);
                        if(r){
                            System.out.println("异步任务延迟调用执行成功,退出!");
                            return;
                        }
                        if(askCount>=3){
                            System.out.println("超过最大调用次数,退出!");
                            return;
                        }

                        scheduleDo();

                    });
                }
            },
            2000//延时2000毫秒
        );
    }

    public static void main(String[] args) {
        System.out.println(asyncDo());
    }
}

然后就可以吧这个写成一个工具类, 这儿用的timer

import lombok.RequiredArgsConstructor;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

@RequiredArgsConstructor
public class AsyncScheduleTimer {
    private final Supplier<Boolean> supplierTask;
    private final Integer maxTryCount;
    private final Integer delayMilliSeconds;

    private Timer _timer ;
    private volatile Integer _tryCount = 0;

    public void asyncDo(){
        CompletableFuture.supplyAsync(() -> {
            return this.supplierTask.get();
        }).whenComplete((r,e)-> {
            if (e != null) {
                System.out.println("异步任务首次调用执行异常,"+e.getMessage());
            }
            else {
                _tryCount++;
                System.out.println("异步任务首次调用执行返回," + r + ",调用次数" + _tryCount);
                if (r) {
                    System.out.println("异步任务调用成功!");
                    return;
                }
                else {
                    System.out.println("异步任务调用失败,进入定时调用");
                    this.initTimer();
                    scheduleDo();
                }
            }
        });
        System.out.println("已经将任务放到异步,主函数返回!");
    }

    private void scheduleDo(){
        this._timer.schedule(
            new TimerTask() {
                @Override
                public void run() {
                    System.out.println("异步任务进入延迟调用执行!");
                    CompletableFuture.supplyAsync(() -> {
                        return supplierTask.get();
                    }).whenComplete((r, e) -> {
                        if (e != null) {
                            System.out.println("异步任务首次调用执行异常," + e.getMessage());
                        } else {
                            _tryCount++;
                            System.out.println("异步任务延迟调用执行返回," + r + ",调用次数" + _tryCount);
                            if (r) {
                                System.out.println("异步任务延迟调用执行成功,退出!");
                                return;
                            }
                            if (_tryCount >= maxTryCount) {
                                System.out.println("超过最大调用次数,退出!");
                                return;
                            }

                            scheduleDo();
                        }

                    });
                }
            },
            this.delayMilliSeconds
        );
    }

    private void initTimer() {
        this._timer = new Timer();
    }

    public static void main(String[] args) {
        new AsyncScheduleTimer(
            ()-> (int)(Math.random() * 100)>80,
            3,
            2000
        ).asyncDo();
    }
}

可以换成 HashedWheelTimer ,关于HashedWheelTimer可以看这个文章http://events.jianshu.io/p/311121f63d2f

import io.netty.util.HashedWheelTimer;
import lombok.RequiredArgsConstructor;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@RequiredArgsConstructor
public class AsyncScheduleHashedWheelTimer {
    private final Supplier<Boolean> supplierTask;
    private final volatile Integer maxTryCount;
    private final Integer delayMilliSeconds;

    private HashedWheelTimer _timer ;
    private volatile Integer _tryCount = 0;

    public void asyncDo(){
        CompletableFuture.supplyAsync(() -> {
            return this.supplierTask.get();
        }).whenComplete((r,e)-> {
            if (e != null) {
                System.out.println("异步任务首次调用执行异常,"+e.getMessage());
            }
            else {
                _tryCount++;
                System.out.println("异步任务首次调用执行返回," + r + ",调用次数" + _tryCount);
                if (r) {
                    System.out.println("异步任务调用成功!");
                    return;
                }
                else {
                    System.out.println("异步任务调用失败,进入定时调用");
                    this.initTimer();
                    scheduleDo();
                }
            }
        });
        System.out.println("已经将任务放到异步,主函数返回!");
    }

    private void scheduleDo(){
        this._timer.newTimeout(
            timeout -> {
                System.out.println("异步任务进入延迟调用执行!");
                CompletableFuture.supplyAsync(() -> {
                    return supplierTask.get();
                }).whenComplete((r,e)-> {
                    if (e != null) {
                        System.out.println("异步任务首次调用执行异常,"+e.getMessage());
                    }
                    else {
                        _tryCount++;
                        System.out.println("异步任务延迟调用执行返回,"+r+",调用次数"+_tryCount);
                        if(r){
                            System.out.println("异步任务延迟调用执行成功,退出!");
                            return;
                        }
                        if(_tryCount>=maxTryCount){
                            System.out.println("超过最大调用次数,退出!");
                            return;
                        }

                        scheduleDo();
                    }

                });
            },
            this.delayMilliSeconds,//延时2000毫秒
            TimeUnit.MILLISECONDS
        );
    }

    private void initTimer() {

//        int[] timeouts = new int[]{this.retryInterval, this.timeout};
//        Arrays.sort(timeouts);
//        int minTimeout = timeouts[0];
//        if (minTimeout % 100 != 0) {
//            minTimeout = minTimeout % 100 / 2;
//        } else if (minTimeout == 100) {
//            minTimeout = 50;
//        } else {
//            minTimeout = 100;
//        }
//
//        this._timer = new HashedWheelTimer(new DefaultThreadFactory(this.poolName), (long)minTimeout, TimeUnit.MILLISECONDS, 1024, false);

        this._timer = new HashedWheelTimer(Executors.defaultThreadFactory(), 100, TimeUnit.MILLISECONDS, 128);
    }

    public static void main(String[] args) {

        new AsyncScheduleHashedWheelTimer(
            ()-> (int)(Math.random() * 100)>80,
            3,
            2000
        ).asyncDo();
    }
}

相关文章

  • Celery 4.3.0 任务失败重试机制

    存在的现象 在异步调用任务中经常需要调用第三方的api请求,如果一次执行失败,则应该进行重试执行。否则,如果在执行...

  • BIO,NIO,AIO

    同步、异步、阻塞、非阻塞 同步与异步 同步: 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。 异步...

  • Spring Retry 详细教程

    什么时候用可以重试 远程调用失败的可以重试 参校失败不应该重试 只读操作可以重试 幂等写操作可以重试 非幂等写操作...

  • spring boot 异步实现@Async

    一、异步与同步 异步调用:程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序; 同步调用:程序按照定义...

  • 阻塞/非阻塞,同步/异步

    同步与异步(线程间调用) 同步与异步是对应于调用者与被调用者,它们是线程之间的关系,两个线程之间要么是同步的,要么...

  • Spring Cloud Gateway重试机制

    前言 重试,我相信大家并不陌生。在我们调用Http接口的时候,总会因为某种原因调用失败,这个时候我们可以通过重试的...

  • 同步与异步

    同步与异步 同步与异步的重点在消息通知的方式上,也就是调用结果通知的方式。 同步: 当一个同步调用发出去后,调用者...

  • 高并发原理

    同步与异步 同步与异步的重点是在消息通知的方式上,也就是调用结果通知的方式上。同步方式是当一个同步调用发出后,调用...

  • 高并发原理研究和探索

    详细了解同步与异步,阻塞与非阻塞。 1、同步与异步 同步与异步的重点在消息通知的方式上,也就是调用结果通知的方式。...

  • 简单理解异步,非阻塞和 IO 复用

    1.1 同步与异步 同步与异步的理解 同步与异步的重点在消息通知的方式上,也就是调用结果通知的方式。同步: 当一个...

网友评论

      本文标题:异步调用与重试

      本文链接:https://www.haomeiwen.com/subject/tsiyldtx.html