异步数据处理公共逻辑记录

场景

目前我们需要对接第三方API,我们需要全量同步一些业务数据,于是编写了一套公共的处理逻辑,此处仅做记录。

代码展示

 /**
     * 任务调度
     * @param fetchFunction 拉取任务
     * @param totalNumFunction 总数获取任务
     * @param storeFunction 存储任务
     * @return 任务是否成功
     */
    public boolean startFetchingAndStoringOrders(Supplier<String> fetchFunction,
                                                 Function<String, Integer> totalNumFunction,
                                                 Consumer<String> storeFunction) {
        final ExecutorService executor = Executors.newFixedThreadPool(2);

        Future<?> fetchFuture = executor.submit(() -> {
            try {
                fetchOrders(fetchFunction, totalNumFunction);
            } catch (Exception e) {
                log.error("Error in fetchOrders", e);
                stopSignal.set(true);
            }
        });

        Future<?> storeFuture = executor.submit(() -> {
            try {
                storeOrders(storeFunction);
            } catch (Exception e) {
                log.error("Error in storeOrders", e);
                stopSignal.set(true);
            }
        });

        try {
            // 等待任务完成
            fetchFuture.get();
            storeFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            log.error("Error waiting for tasks to complete", e);
            return false;
        } finally {
            executor.shutdown();
            try {
                if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                    List<Runnable> droppedTasks = executor.shutdownNow();
                    log.info("Executor did not terminate in the specified time.");
                    log.info("Dropped " + droppedTasks.size() + " tasks.");
                }
            } catch (InterruptedException ie) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        return goalSignal.get();
    }


    /**
     * 公共拉取逻辑
     *
     * @param fetchFunction    不用的订单 不同的拉取方式
     * @param totalNumFunction 不同的json,不同的总数处理方式
     */
    private void fetchOrders(Supplier<String> fetchFunction,
                             Function<String, Integer> totalNumFunction) throws Exception {
        try {
            int pageNumber = 1;
            int totalNum = 0;
            do {
                String json = fetchFunction.get(); // 获取数据
                totalNum = totalNumFunction.apply(json); // 从 JSON 中获取总数
                queue.put(json); // 将 JSON 字符串放入队列
                pageNumber++;
            } while (pageNumber * PAGE_SIZE < totalNum && !stopSignal.get());
        } catch (Exception e) {
            log.error("Error during fetching orders", e);
            stopSignal.set(true);
            goalSignal.set(false);
            throw e; // 抛出异常
        }
        goalSignal.set(true);
    }


    /**
     * 数据处理逻辑
     * @param storeFunction 存储实现
     * @throws Exception 异常
     */
    private void storeOrders(Consumer<String> storeFunction) throws Exception {
        while (true) { // 永久循环,直到显式退出
            if (stopSignal.get()){
                break;
            }
            if (queue.isEmpty() && goalSignal.get()) {
                // 如果队列为空且生产者已完成,则退出循环
                break;
            }
            try {
                String jsonOrder = queue.poll(1, TimeUnit.SECONDS); // 尝试从队列中取出数据,设置超时避免永久阻塞
                if (jsonOrder != null) {
                    storeFunction.accept(jsonOrder); // 如果有数据,则处理
                }
            } catch (Exception e) {
                log.error("Error while taking from the queue", e);
                stopSignal.set(true);
                goalSignal.set(false);
                throw e; // 抛出异常
            }
        }
    }

startFetchingAndStoringOrders 方法:

使用两个异步任务:一个用于获取数据(fetchOrders),另一个用于存储数据(storeOrders)。
使用 Future 来跟踪这两个任务的执行状态。
如果任一任务遇到异常,通过 stopSignal 通知另一个任务停止执行。
最后返回 goalSignal.get(),表明任务是否成功完成。
fetchOrders 方法:

循环获取数据,每次迭代调用 fetchFunction 获取 JSON 数据,并使用 totalNumFunction 从中提取总数信息。
将获取的数据放入 queue。
如果遇到异常,设置 stopSignal 和 goalSignal,并抛出异常。
storeOrders 方法:

不断从 queue 中取数据并处理。如果 queue 为空,等待最多1秒。
如果检测到 stopSignal 或 goalSignal 且队列为空,则终止循环。
如遇异常,设置 stopSignal 和 goalSignal,并抛出异常。

功能阐述

生产者-消费者模型:优化的多线程处理,实现数据的高效拉取和存储。
动态数据处理:支持不同的数据源和存储策略(自行实现),增加灵活性。
异常处理:增强的错误监控,确保流程的稳健性和可靠性。
同步机制:通过 AtomicBoolean 实现跨任务的同步控制,优雅地处理任务终止情况。
精确队列管理:使用 BlockingQueue 管理数据流,避免了生产者和消费者之间的潜在阻塞问题。
自适应任务结束:合理地处理队列空状态,确保所有数据被处理后任务能够自动结束。

待优化点

优化等待策略,减少无效的等待和性能损失。

结束语

记录一次异步数据处理公共逻辑

你可能感兴趣的:(JAVA框架,java)