文件下载时利用redis的队列模式顺序下载文件,防止多文件任务下载导致OOM

news2025/1/19 23:56:05

1、controller层控制


@Resource
    private RedissonClient redissonClient;
	@Slf4j
@Service
public class CustomerSettlementExportServiceImpl implements ICustomerSettlementExportService {
/**
     * 文件加入队列顺序导出
     *
     * @param pubFileExportList 参数
     * @return 结果
     */
    public AjaxResult pubFileExport(List<PubFileExport> pubFileExportList) {
        if (CollectionUtils.isEmpty(pubFileExportList)) {
            return AjaxResult.error("客户信息不能为空!");
        }
        RQueue<String> queue = redissonClient.getQueue("downloadQueue:file:export");
        for (PubFileExport pubFileExport : pubFileExportList) {
            try {
                queue.add(JSONObject.toJSONString(pubFileExport));
            } catch (Exception e) {
                log.error("加入队列失败=", e);
                return AjaxResult.error("添加导出任务到队列失败!");
            }
        }
        return AjaxResult.success();
    }
}

以下代码是通过定时任务拉取队列进行文件下载

@Slf4j
@Service
public class FileDownloadServiceImpl implements IFileDownloadService {

    @Resource
    private ICustomerSettlementExportService customerSettlementExportService;

    @Resource
    private IPubFileExportService pubFileExportService;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private RedissonClient redissonClient;

    @Scheduled(fixedRate = 10000)
    public void processDownloadsInit() {
        // 提前过滤掉特定 IP 地址
        if (isLocalIp()) {
            return;
        }
        RLock lock = null;
        try {
            lock = redissonClient.getLock(BmsConstants.QUEUE_KEY_LOCK);
            boolean isOrderLock = lock.tryLock(10, TimeUnit.SECONDS);
            if (!isOrderLock) {
                // 当前任务未执行完,不能获取锁
                log.error("未能获取分布式锁,当前任务未执行完或有其他实例正在执行");
                return;
            }
            // 阻塞获取队列中的任务
            String exportTask = redisTemplate.opsForList().rightPop(BmsConstants.QUEUE_KEY, 10, TimeUnit.SECONDS);
            if (exportTask != null) {
                log.info("队列文件下载开始=" + DateUtils.getTime());
                handleDownload(exportTask);
                log.info("队列文件下载结束=" + DateUtils.getTime());
            }
        } catch (Exception e) {
            log.error("队列文件下载异常=", e);
        } finally {
            safeUnlock(lock);
        }
    }

    /**
     * 执行队列文件下载
     *
     * @param exportTask 导出参数
     */
    private void handleDownload(String exportTask) {
        try {
            PubFileExport pubFileExport = JSONObject.parseObject(exportTask, PubFileExport.class);
            // 实际的文件下载逻辑
            if (pubFileExport.getExportStartTime() == null
                    || pubFileExport.getExportEndTime() == null
                    || StringUtils.isBlank(pubFileExport.getClientCode())) {
                log.error("客户数据文件下载的参数为空请检查!");
                return;
            }
            AjaxResult ajaxResult = customerSettlementExportService.exportSheets(pubFileExport);
            pubFileExportService.updateExportAllExcel(ajaxResult, pubFileExport.getGid(), pubFileExport.getFinalUrl());
        } catch (Exception e) {
            log.error("执行队列文件下载异常=", e);
        }
    }

    /**
     * 检查是否为本地 IP 地址
     *
     * @return 是否为本地 IP 地址
     */
    private boolean isLocalIp() {
        try {
            InetAddress localAddress = InetAddress.getLocalHost();
            String ip = localAddress.getHostAddress();
            return ip.startsWith("192.168");
        } catch (Exception e) {
            log.error("获取本地 IP 地址异常=", e);
            return false;
        }
    }

    /**
     * 安全释放锁
     *
     * @param lock 锁对象
     */
    private void safeUnlock(RLock lock) {
        if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
            try {
                lock.unlock();
            } catch (Exception e) {
                log.error("释放锁异常=", e);
            }
        }
    }

}

3、解析下代码

这段代码实现了文件下载任务的队列管理和处理。
主要功能包括:
任务入队:将多个文件导出任务加入Redis队列。
定时任务处理:每隔10秒从队列中取出任务并执行文件下载。
分布式锁控制:确保同一时间只有一个实例处理任务,避免重复执行。
本地IP过滤:防止本地IP地址触发任务。

控制流图(CFG)

flowchart TD
A[开始] --> B{是否为本地IP}
B -->|是| E[结束]
B -->|否| C[获取分布式锁]
C --> D{是否获取成功}
D -->|否| F[记录日志并结束]
D -->|是| G[从队列取任务]
G --> H{是否有任务}
H -->|否| I[释放锁并结束]
H -->|是| J[处理下载任务]
J --> K[记录开始时间]
K --> L[调用下载逻辑]
L --> M[记录结束时间]
M --> N[释放锁并结束]

详细说明

任务入队 (pubFileExport 方法):
检查任务列表是否为空。
将每个任务序列化后加入Redis队列。
定时任务处理 (processDownloadsInit 方法):
检查是否为本地IP地址,如果是则直接返回。
尝试获取分布式锁,如果失败则记录日志并返回。
从Redis队列中取出任务,如果有任务则调用处理方法。
记录任务开始和结束时间,并释放锁。
处理下载任务 (handleDownload 方法):
反序列化任务参数。
检查参数是否完整,如果不完整则记录错误并返回。
调用客户结算导出服务进行文件下载,并更新导出状态。
辅助方法:
isLocalIp:检查当前IP是否为本地IP。
safeUnlock:安全释放分布式锁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2279117.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

.Net 6.0 .Net7.0 .Net8.0 .Net9.0 使用 Serilog 按日志等级写入日志及 appsetting.json 配置方式实现

前言 最近使用最新版的Serilog记录日志时&#xff0c;发现以前有些关于Serilog的Nuget弃用了&#xff0c;最关键的是有些配置写法也改变&#xff0c;于是就整理了一下最新版的Serilog配置方式(appsetting.json)的使用 说明&#xff1a;我是用的.Net6&#xff0c;最新长期支持…

数字化时代,传统代理模式的变革之路

在数字化飞速发展的今天&#xff0c;线上线下融合&#xff08;O2O&#xff09;成了商业领域的大趋势。这股潮流&#xff0c;正猛烈冲击着传统代理模式&#xff0c;给它带来了新的改变。 咱们先看看线上线下融合现在啥情况。线上渠道那是越来越多&#xff0c;企业纷纷在电商平台…

wireshark上没有显示出来rtp协议如何处理

分析》启用的协议 搜索rtp&#xff0c;勾选上rtp_udp即可。

edge浏览器恢复旧版滚动条

1、地址栏输入edge://flags 2、搜索Fluent scrollbars.&#xff0c;选择disabled&#xff0c;重启即可

使用 Java 和 FreeMarker 实现自动生成供货清单,动态生成 Word 文档,简化文档处理流程。

在上一篇博客中主要是使用SpringBootApache POI实现了BOM物料清单Excel表格导出&#xff0c;详见以下博客&#xff1a; Spring Boot Apache POI 实现 Exc&#xff08;&#xff09;el 导出&#xff1a;BOM物料清单生成器&#xff08;支持中文文件名、样式美化、数据合并&#…

二进制/源码编译安装mysql 8.0

二进制方式&#xff1a; 1.下载或上传安装包至设备&#xff1a; 2.创建组与用户&#xff1a; [rootopenEuler-1 ~]# groupadd mysql [rootopenEuler-1 ~]# useradd -r -g mysql -s /bin/false mysql 3.解压安装包&#xff1a; tar xf mysql-8.0.36-linux-glibc2.12-x86_64.ta…

VB.net实战(VSTO):解决WPS Ribbon图标灰色背景

问题&#xff1a;用VSTO制作插件&#xff0c;在MS Office中图标显示正常&#xff0c;但在WPS Office中图标显示为灰色背景 原因&#xff1a;使用的图标是纯透明背景的&#xff0c;这样的图标在WPS中会变为灰色背景。 以下这个解决办法是我自己摸索出来的&#xff0c;对您有用的…

搭建一个基于Spring Boot的书籍学习平台

搭建一个基于Spring Boot的书籍学习平台可以涵盖多个功能模块&#xff0c;例如用户管理、书籍管理、学习进度跟踪、笔记管理、评论和评分等。以下是一个简化的步骤指南&#xff0c;帮助你快速搭建一个基础的书籍学习平台。 — 1. 项目初始化 使用 Spring Initializr 生成一个…

金融项目实战 06|Python实现接口自动化——日志、实名认证和开户接口

目录 一、日志封装及应用&#xff08;理解&#xff09; 二、认证开户接口脚本编写 1、代码编写 1️⃣api目录 2️⃣script目录 2、BeautifulSoup库 1️⃣简介及例子 2️⃣提取html数据工具封装 3、认证开户参数化 一、日志封装及应用&#xff08;理解&#xff09; &…

Sqlmap入门

原理 在owasp发布的top10 漏洞里面&#xff0c;注入漏洞一直是危害排名第一&#xff0c;其中数据库注入漏洞是危害的。 当攻击者发送的sql语句被sql解释器执行&#xff0c;通过执行这些恶意语句欺骗数据库执行&#xff0c;导致数据库信息泄漏 分类 按注入类型 常见的sql注入…

Maven在Win10上的安装教程

诸神缄默不语-个人CSDN博文目录 这个文件可以跟我要&#xff0c;也可以从官网下载&#xff1a; 第一步&#xff1a;解压文件 第二步&#xff1a;设置环境变量 在系统变量处点击新建&#xff0c;输入变量名MAVEN_HOME&#xff0c;变量值为解压路径&#xff1a; 在系统变…

C# OpenCvSharp 部署3D人脸重建3DDFA-V3

目录 说明 效果 模型信息 landmark.onnx net_recon.onnx net_recon_mbnet.onnx retinaface_resnet50.onnx 项目 代码 下载 参考 C# OpenCvSharp 部署3D人脸重建3DDFA-V3 说明 地址&#xff1a;https://github.com/wang-zidu/3DDFA-V3 3DDFA_V3 uses the geometri…

SpringMVC (2)

目录 1. RequestMapping 注解介绍 2. RequestMapping 使用 3. RequestMapping与请求方式 3.1 RequestMapping 支持Get和Post类型的请求 3.2 RequestMapping 指定接收某种请求 3.3 GetMapping和PostMapping 4. 传参 4.1 通过查询字符串传参 4.2 在 Body 中传参 4.2.1 …

Python爬虫学习前传 —— Python从安装到学会一站式服务

早上好啊&#xff0c;大佬们。我们的python基础内容的这一篇终于写好了&#xff0c;啪唧啪唧啪唧…… 说实话&#xff0c;这一篇确实写了很久&#xff0c;一方面是在忙其他几个专栏的内容&#xff0c;再加上生活学业上的事儿&#xff0c;确实精力有限&#xff0c;另一方面&…

力扣 打家劫舍

动态规划&#xff0c;当前状态由前两个状态获得&#xff0c;滚动数组。 题目 从题可以看出要达到最高金额时&#xff0c;要从相邻的房屋拿。因此是当前房屋的金额隔一个做累加&#xff0c;当然还需要跟前一个相邻的房屋做比较&#xff0c;便于取到哪边金额更高&#xff0c;因此…

Banana Pi BPI-RV2 RISC-V路由开发板采用矽昌通信SF2H8898芯片

Banana Pi BPI-RV2 开源网关是⼀款基于矽昌SF2H8898 SoC的设备&#xff0c;1 2.5 G WAN⽹络接⼝、5 个千兆LAN ⽹络接⼝、板载 512MB DDR3 内存 、128 MiB NAND、16 MiB NOR、M.2接⼝&#xff0c;MINI PCIE和USB 2.0接⼝等。 Banana Pi BPI-RV2 开源网关是矽昌和⾹蕉派开源社…

ESP8266-01S、手机、STM32连接

1、ESP8266-01S的工作原理 1.1、AP和STA ESP8266-01S为WIFI的透传模块&#xff0c;主要模式如下图&#xff1a; 上节说到&#xff0c;我们需要用到AT固件进行局域网应用&#xff08;ESP8266连接的STM32和手机进行连接&#xff09;。 ESP8266为一个WiFi透传模块&#xff0c;和…

【BUUCTF】[GXYCTF2019]BabySQli

进入页面如下 尝试万能密码注入 显示这个&#xff08;qyq&#xff09; 用burp suite抓包试试 发现注释处是某种编码像是base编码格式 MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5 可以使用下面这个网页在线工具很方便…

CSS基础知识 ----- 学习

介绍 CSS&#xff08;Cascading Style Sheets&#xff09;是一种用于定义网页样式和布局的样式表语言。 它与 HTML 一起用于构建 Web 页面&#xff0c;HTML 负责定义页面的结构和内容&#xff0c;而 CSS 则负责控制页面的外观和样式(各种元素的字体,颜色,大小,间距,边距)。 …

计算机网络 (50)两类密码体制

前言 计算机网络中的两类密码体制主要包括对称密钥密码体制&#xff08;也称为私钥密码体制、对称密码体制&#xff09;和公钥密码体制&#xff08;也称为非对称密码体制、公开密钥加密技术&#xff09;。 一、对称密钥密码体制 定义&#xff1a; 对称密钥密码体制是一种传…