如何判断接口数据请求超时?

1. 业务背景

现有一个任务是通过异步去远程请求一个服务的数据,并等待该服务调用接口返回数据,在这个过程中如何判断请求的数据能够在规定时间内返回呢?

2. 处理方法

2.1  利用Redis来实现超时控制

1)在请求远程方法的时候,将该操作ID保存到数据库中,并设置超时时间

if (parseMap.containsKey("code") && String.valueOf(parseMap.get("code")).equals("201")){
    // 缓存到redis中,用于定时器查询接口返回结果
    redisTemplate.opsForValue().set(ReceiveService.ESIM_REMOTE_QUEUE_CACHE + uuid, uuid, ReceiveService.ESIM_REMOTE_TIMEOUT, TimeUnit.MINUTES);
}

2)在redis的配置文件中打开配置选项:搜索:notify-keyspace-events Ex 找到后,放开注释,保存。其作用就是开启redis监听key过期通知。

3)针对redis数据丢失事件,进行数据处理。

public class RedisKeyExpirationListener extends MessageListenerAdapter {

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }
    /**
     * 针对redis数据失效事件,进行数据处理
     */
    @Override
    public void onMessage(Message message, byte[] topic) {
        String key = message.toString();
        if(StringUtils.isNotBlank(key) && key.contains(ReceiveService.ESIM_REMOTE_QUEUE_CACHE)) {
                //去掉前缀,并放入失效列表
                key = key.replaceAll(ReceiveService.ESIM_REMOTE_QUEUE_CACHE,"");
                redisTemplate.opsForList().rightPush(ReceiveService.ESIM_REMOTE_QUEUE_CACHE, key);
        }
    }
 
    public boolean lockBySecondsTime(String key, long expirationTime){
        //  此方法只适用于在 expirationTime 时间段内进行锁竞争的场景。如果超过 expirationTime 时间段,
        //  锁自动失效,之前获取到锁的线程还在运行,就失去了分布式锁的意义,慎重根据自己的场景来使用。
        Long timeStamp = new Date().getTime() + (expirationTime * 1000);
        // 通过setNx获取锁
        return ifAbsent(key, String.valueOf(timeStamp), expirationTime, TimeUnit.SECONDS);
    }
 
    public boolean ifAbsent(String key, String value, long expirationTime , TimeUnit timeUnit) {
        Boolean res = (Boolean) redisTemplate.execute(new RedisCallback() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.stringCommands().set(key.getBytes(), value.getBytes(),
                        Expiration.from(expirationTime, timeUnit), RedisStringCommands.SetOption.ifAbsent());
            }
        });
        return res == null ? false : res;
    }
}

4)当数据被放入失效列表的时候,我们需要有一个定时任务随时监听这个列表,并对其进行处理。

@Component
public class RedisKeyExpirationThread implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private TestService testService;
    @Autowired
    private RedisTemplate redisTemplate;

    private static ApplicationContext applicationContext;

    //任务处理
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if(event.getApplicationContext().getParent() == null) {
            applicationContext = event.getApplicationContext();
            // 创建线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Thread.currentThread().setName("RedisKeyExpirationThread");
                    while (true) {
                        try {
                            String key = (String) redisTemplate.opsForList().leftPop(ReceiveService.ESIM_REMOTE_QUEUE_CACHE);
                            if (StringUtils.isNotBlank(key)) {
                                System.out.println("Expiration Key: " + key);
                                key = key.replaceAll(ReceiveService.ESIM_REMOTE_QUEUE_CACHE, ""); //得到操作ID
                                testService.handleTimeout(key);
                            }else {
                                Thread.sleep(10 * 1000);
                            }
                        } catch (Exception exception) {
                            exception.printStackTrace();
                        } finally {
                            try {
                                Thread.sleep(3 * 1000);
                            } catch (Exception e2) {
                                e2.printStackTrace();
                            }
                        }
                    }
                }
            }).start();
        }
    }
}

2.2 利用MySQL数据库来实现超时控制

1)在远程调用接口获取数据时,需要保存调用时间;

2)启用一个定时器多久轮询一次,查询数据库的数据;

3)用当前时间减去一开始保存的调用时间,判断是否超时来进行数据处理。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Timer;
import java.util.TimerTask;

public class TimeoutControlWithMySQL {

    private static final String URL = "jdbc:mysql://your_host:your_port/your_database";
    private static final String USER = "your_username";
    private static final String PASSWORD = "your_password";

    public static void main(String[] args) {
        // 记录调用时间并插入到数据库
        long callTime = System.currentTimeMillis();
        insertCallTime(callTime);

        // 启动定时器进行轮询
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                checkTimeout();
            }
        }, 0, 5000); // 每 5 秒轮询一次
    }

    private static void insertCallTime(long callTime) {
        try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
             PreparedStatement stmt = conn.prepareStatement("INSERT INTO call_times (timestamp) VALUES (?)")) {
            stmt.setLong(1, callTime);
            stmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static void checkTimeout() {
        try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
             PreparedStatement stmt = conn.prepareStatement("SELECT timestamp FROM call_times LIMIT 1");
             ResultSet rs = stmt.executeQuery()) {
            if (rs.next()) {
                long callTime = rs.getLong("timestamp");
                long currentTime = System.currentTimeMillis();
                if (currentTime - callTime > 10000) { // 假设超时时间为 10 秒
                    // 进行超时处理
                    System.out.println("超时,进行数据处理...");
                } else {
                    System.out.println("未超时");
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

在Vue中,要判断接口数据量是否过多并且是否超时,可以通过以下方法进行判断: 1. 使用异步请求并设置超时时间:Vue通常会使用axios或者fetch等第三方库进行数据请求,这些库都支持设置超时时间。在请求接口时,可以设置一个适当的超时时间,如果在规定时间内没有接收到响应,就认为接口数据量过多并且超时了。 2. 使用加载状态进行判断:在异步请求接口之前可以设置一个加载状态,当接收到响应或者超时时,可以根据加载状态进行判断。例如,可以在请求开始时将加载状态设置为"loading",当接口请求成功或者超时时将加载状态设置为"success"或者"timeout"。根据加载状态可以对接口数据量进行判断和处理。 3. 设置接口请求时间戳:可以在每次发送接口请求前获取当前的时间戳,然后保存下来。当接口返回响应后,再次获取当前时间戳,并与初始时间戳进行比较。如果时间差超过一个合理的范围(根据实际情况来定),则可以认为接口数据量过多并且超时了。 4. 使用响应拦截器:Vue的第三方库如axios支持拦截器的使用,可以在请求发送前和响应返回后进行拦截处理。可以在拦截器中进行接口请求的开始和结束时间的计算,以及判断接口数据量是否过多并且超时。 以上是几种判断接口数据量过多并且超时的方法,在实际应用中可以根据具体情况选择合适的方法进行判断和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值