如何实现设备组缓存的正确清除?——基于心跳请求和心跳响应的解决方案

目录

  • 一、问题描述
  • 二、问题分析
  • 三、解决方案
    • 前端
    • 后端

在设备组关闭后,如何保证缓存中的设备组信息能够正确清除?本文将介绍如何通过前端实现设备组心跳检测和缓存清除,以及通过后端实现缓存清除的逻辑来解决该问题。我们还将详细讨论如何利用心跳请求和心跳响应来实现设备组缓存的正确清除,并提供基于Vue和SpringBoot的代码示例。

一、问题描述

在开发设备管理系统时,我们经常需要保证设备组在关闭后能够从缓存中正确删除,以避免占用过多的系统资源。

示例:若依前后端分离框架,如果用户使用当前设备组,那么当前设备组会被写进缓存里,然后被占用,其他用户则不能使用该设备组;如果用户退出当前设备组,那么将从缓存里删掉该设备,但是很难保证的情况是,如果用户突然关闭浏览器,或者不正常关闭页面、退出帐号,都不能正常从缓存里删除该设备组,如何保证不管怎么样退出,都能从缓存中删掉该设备组?

二、问题分析

前端使用一个定时器,每隔5秒向后端发送请求,告知后端当前设备组是否还在使用中。后端使用一个DEVICE_GROUP_KEY + id来保存设备组是否被占用的状态,当用户加入设备组时,将该设备组的状态设置为占用,并设定过期时间为10秒;当用户退出设备组时,从DEVICE_GROUP_KEY + id中删除该设备组的状态。如果后端收到了一段时间内没有收到定时器请求的设备组,就会自动将该设备组从DEVICE_GROUP_KEY + id中删除。

当用户正常退出设备组时,前端会清除定时器并向后端发送请求,告知后端该设备组已经退出使用。如果用户异常退出设备组,则后端会在一段时间后自动删除该设备组。

三、解决方案

你的前端代码看起来已经调用了后端接口将设备组放入缓存中了。如果你想实现定时向后端发送请求,告知后端该设备组是否还在使用中,可以使用setInterval函数创建一个定时器,每隔一定时间向后端发送请求,告知后端该设备组仍在使用中。

前端

deviceInfo是预选设备组,currentDeviceInfo是当前设备组,deviceGroupKeys是缓存中的设备组,代码示例如下:

<template><div><el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="60px"><el-form-item label="设备组" prop="group"><el-select v-model="deviceGroup" placeholder="请选择" @change="selectDeviceGroup"><!-- 选择deviceGroupList --><el-option v-for="item in deviceGroupList" :key="item.deviceGroup" :label='"第" + item.deviceGroup + "组"':value="item.deviceGroup" /></el-select></el-form-item><el-form-item><el-button type="primary" icon="el-icon-circle-check" size="mini" @click="joinDeviceGroup">确定</el-button><el-button icon="el-icon-remove-outline" size="mini" type="info" @click="leaveDeviceGroup">退出当前设备组</el-button></el-form-item></el-form></div>
</template>
    /** 加入设备组 */async joinDeviceGroup(){//查询预选的设备组是否被占用if (this.deviceGroupKeys.includes(`${this.deviceInfo.deviceGroup}`)) {this.$message({message: "该设备组已被使用",type: "warning",});return;}//预选设备组没有被占用,如果当前设备组被自己占用,则将其从缓存中删除if (this.currentDeviceInfo.deviceGroup !== "") {await deleteDeviceGroupKey(this.currentDeviceInfo.deviceGroup);clearInterval(this.timer);}//否则将deviceInfo预选设备组放入currentDeviceInfo当前设备组this.currentDeviceInfo = JSON.parse(JSON.stringify(this.deviceInfo)) || null;// 将currentDeviceInfo中的deviceGroup放入缓存,用setDeviceGroupKey方法await setDeviceGroupKey(this.currentDeviceInfo.deviceGroup);// 开启定时器this.setInterval();}
    /** 定义一个定时器,每隔5秒钟,调用一次sendDeviceHeartbeat方法 */setInterval() {// 如果currentDeviceInfo.deviceGroup为空,则停止定时器if (this.currentDeviceInfo.deviceGroup == "") {clearInterval(this.timer);} else {this.timer = setInterval(() => {this.sendDeviceHeartbeat();}, 5000);}},// 发送心跳请求的函数sendDeviceHeartbeat() {// 如果this.currentDeviceInfo.deviceGroup为空,则停止定时器if (this.currentDeviceInfo.deviceGroup == "") {clearInterval(this.timer);}// 发送请求deviceHeartBeatdeviceHeartBeat(this.currentDeviceInfo.deviceGroup).then((response) => {// console.log(response);if (response === 0) {// 心跳成功,设备组仍在使用中} else {// 心跳失败,设备组已经退出使用this.$message({message: "设备组已经退出使用",type: "warning",});clearInterval(this.timer);}});},

然后在用户正常退出设备组时,清除定时器并向后端发送请求,告知后端该设备组已经退出使用。代码示例如下:

leaveDeviceGroup() {if (this.currentDeviceInfo.deviceGroup != "") {deleteDeviceGroupKey(this.currentDeviceInfo.deviceGroup).then((response) => {//清空currentDeviceInfothis.currentDeviceInfo = {deviceGroup: "",};});}// 停止定时器clearInterval(this.timer);
}

计时器应该在用户正常退出设备组和关闭页面时被清除。在Vue中,可以通过在beforeDestroy()生命周期钩子中清除计时器,例如:

beforeDestroy() {clearInterval(this.timer);
}

这里假设你的计时器是通过setInterval()创建的,并将其存储在Vue实例的timer属性中。当Vue实例被销毁时,beforeDestroy()生命周期钩子会被调用,此时可以清除计时器。

后端

获取缓存中deviceGroup所有的key

    /*** 获取缓存中deviceGroup所有的key*/@GetMapping("/getDeviceGroupKeys")public List<Integer> getDeviceGroupKeys() {//将redis中device_group的的基本对象列表,使用redisCache.keys()方法获取String[] keys = redisCache.keys(CacheConstants.DEVICE_GROUP_KEY + "*").toArray(new String[0]);//将keys中的值,去掉前缀,只保留1,2,3,4,5List<Integer> list = new ArrayList<>();for (String key : keys) {list.add(Integer.parseInt(key.substring(CacheConstants.DEVICE_GROUP_KEY.length())));}//将list从小到大排序list.sort((o1, o2) -> o1 - o2);return list;}

实现将设备组放入缓存

    /*** 将设备组放入缓存*/@GetMapping(value = "/setDeviceGroupKey/{id}")public String setDeviceGroupKey(@PathVariable("id") Integer id) {redisCache.setCacheObject(CacheConstants.DEVICE_GROUP_KEY + id, "true", 10, TimeUnit.SECONDS);return redisCache.hasKey(CacheConstants.DEVICE_GROUP_KEY + id) ? "true" : "false";}

在用户正常退出设备组时,你可以实现一个deleteDeviceGroupKey接口,用于从缓存中删除该设备组。代码示例如下:

    /*** 将设备组从缓存中删除*/@GetMapping("/deleteDeviceGroupKey/{id}")public String deleteDeviceGroupKey(@PathVariable("id") Integer id) {redisCache.deleteObject(CacheConstants.DEVICE_GROUP_KEY + id);return redisCache.hasKey(CacheConstants.DEVICE_GROUP_KEY + id) ? "false" : "true";}

你可以实现一个deviceHeartBeat接口,用于更新设备组在缓存中的存活时间。代码示例如下:

    /*** 检查设备组是否还在使用,心跳请求处理接口*/@PostMapping(value = "/deviceHeartBeat/{id}")public String deviceHeartBeat(@PathVariable("id") Integer id) {// 检查设备组是否存在于缓存中if (!redisCache.hasKey(CacheConstants.DEVICE_GROUP_KEY + id)) {// 设备组不存在,返回心跳失败return "Device group not found!";} else {// 更新设备组的心跳时间redisCache.expire(CacheConstants.DEVICE_GROUP_KEY + id, 10, TimeUnit.SECONDS);// 返回心跳成功return "Heartbeat successfully!";}}

如果用户异常退出设备组,你可以在后端实现一个定时任务,定时检查缓存中的设备组是否过期,如果过期则删除该设备组。代码示例如下:

	/*** 定时任务:删除过期的设备组,每隔10秒检查一次缓存中的设备组是否超时*/@Scheduled(fixedDelay = 10000)public void checkDeviceGroupKey() {// 获取当前时间Date now = new Date();Set<Object> deviceGroupKeys = redisCache.keys(CacheConstants.DEVICE_GROUP_KEY + "*");// 遍历缓存中的设备组DEVICE_GROUP_KEY,检查是否超时for (Object deviceGroupKey : deviceGroupKeys) {// 获取缓存中的设备组String key = (String) deviceGroupKey;// 如果缓存中的设备组存在if (redisCache.hasKey(key)) {// 获取缓存中的设备组的最后一次心跳时间Date lastHeartBeatTime = redisCache.getCacheObject(key);// 计算当前时间和最后一次心跳时间的差值long diff = now.getTime() - lastHeartBeatTime.getTime();// 如果差值大于10秒,说明设备组已经超时,将设备组从缓存中删除if (diff > 10000) {redisCache.deleteObject(key);}}}}

也可以限制哪几个设备组需要被清除

    /*** 定时任务:删除过期的设备组,每隔10秒检查一次缓存中的设备组是否超时*/@Scheduled(fixedDelay = 10000)public void checkDeviceGroupKey() {// 获取当前时间Date now = new Date();// 遍历缓存中的设备组DEVICE_GROUP_KEY,检查是否超时for (int i = 1; i <= 16; i++) {// 获取缓存中的设备组String key = CacheConstants.DEVICE_GROUP_KEY + i;// 如果缓存中的设备组存在if (redisCache.hasKey(key)) {// 获取缓存中的设备组的最后一次心跳时间Date lastHeartBeatTime = redisCache.getCacheObject(key);// 计算当前时间和最后一次心跳时间的差值long diff = now.getTime() - lastHeartBeatTime.getTime();// 如果差值大于10秒,说明设备组已经超时,将设备组从缓存中删除if (diff > 10000) {redisCache.deleteObject(key);}}}}

后端缓存时间设置为10秒钟,前端每隔5秒向后端发送请求,那么在正常情况下,如果前端正常关闭,后端会在10秒钟后自动清除该设备组的缓存。

如果前端异常关闭,那么后端会在10秒钟后检测到该设备组的心跳信号已经停止,然后自动清除该设备组的缓存。

因此,这种方法可以保证在大多数情况下能够及时清除缓存,但是仍然可能存在一些极端情况导致缓存无法及时清除,比如网络故障等。

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

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

相关文章

ROS2 库包设置和使用 Catch2 进行单元测试

说明 本文的目的是了解如何在 ROS2 中创建库&#xff0c;以供其他 ROS2 包使用。除此之外&#xff0c;本文还介绍了如何使用 catch2 框架编写单元测试。本文的第 1 部分将详细介绍如何创建库包。第 2 部分将介绍 ROS2 软件包如何利用创建的库 上篇 ROS2 库包设置和使用 Catch2…

GEO生信数据挖掘(一)数据集下载和初步观察

检索到目标数据集后&#xff0c;开始数据挖掘&#xff0c;本文以阿尔兹海默症数据集GSE1297为例 目录 GEOquery 简介 安装并加载GEOquery包 getGEO函数获取数据&#xff08;联网下载&#xff09; 更换下载数据源 对数据集进行初步观察处理 GEOquery 简介 GEOquery是一个…

【AntDesign】封装全局异常处理-全局拦截器

[toc] 场景 本文前端用的是阿里的Ant-Design框架&#xff0c;其他框架也有全局拦截器&#xff0c;思路是相同&#xff0c;具体实现自行百度下吧 因为每次都需要调接口&#xff0c;都需要单独处理异常情况&#xff08;code !0&#xff09;&#xff0c;因此前端需要对后端返回的…

联邦学习-Tensorflow实现联邦模型AlexNet on CIFAR-10

目录 Client端 Server端 扩展 Client.py Server.py Dataset.py Model.py 分享一种实现联邦学习的方法&#xff0c;它具有以下优点&#xff1a; 不需要读写文件来保存、切换Client模型 不需要在每次epoch重新初始化Client变量 内存占用尽可能小&#xff08;参数量仅翻一…

1.4.C++项目:仿muduo库实现并发服务器之buffer模块的设计

项目完整版在&#xff1a; 一、buffer模块&#xff1a; 缓冲区模块 Buffer模块是一个缓冲区模块&#xff0c;用于实现通信中用户态的接收缓冲区和发送缓冲区功能。 二、提供的功能 存储数据&#xff0c;取出数据 三、实现思想 1.实现换出去得有一块内存空间&#xff0c;采…

Learning Invariant Representation for Unsupervised Image Restoration

Learning Invariant Representation for Unsupervised Image Restoration (Paper reading) Wenchao Du, Sichuan University, CVPR20, Cited:63, Code, Paper 1. 前言 近年来&#xff0c;跨域传输被应用于无监督图像恢复任务中。但是&#xff0c;直接应用已有的框架&#xf…

【python海洋专题三】图像修饰之画布和坐标轴

【python海洋专题三】图像修饰之画布和坐标轴 海洋与大气科学 上期读取nc水深文件&#xff0c;并出图 但是存在一些不完美&#xff0c;本期修饰 本期内容目录 1&#xff1a;改变画布大小 2&#xff1a;改变画布背景色 3&#xff1a;改变画布在显示屏中的显示位置 4&#xf…

【项目管理】--敏捷开发管理之Scrum

目录 一、前言二、what---敏捷开发是什么2.1、敏捷开发宣言2.2、敏捷开发原则2.3、一句话概述敏捷开发三、why---为什么会有敏捷开发3.1、传统开发模式和敏捷开发模式对比四、how---敏捷开发怎么实践到项目团队4.1、what---Scrum是什么4.2、what---Scrum有哪些内容(1)、Scrum之…

NLP 01(介绍)

一、NLP 自然语言处理 (Natural Language rrocessing,简称NLP) 是计算机科学与语言学中关注于计算机与人类语言间转换的领域。 1.1 发展 规则&#xff1a;基于语法 自然语言处理的应用场景: 语音助手 机器翻译 搜索引擎 智能问答

【单片机】12-串口通信和RS485

1.通信有关的常见概念 区分&#xff1a;串口&#xff0c;COM口&#xff0c;UART&#xff0c;USART_usart和串口区别-CSDN博客 串口、COM口、UART口, TTL、RS-232、RS-485区别详解-CSDN博客 1.什么是通信 &#xff08;1&#xff09;人和人之间的通信&#xff1a;说话&#xff…

抓包习讯云院校数据通过PHP解析导入数据库

前言 最近&#xff0c;打卡APP需要这个数据&#xff0c;通过抓包后发现这个数据是固定的&#xff0c;获取很简单&#xff0c;但是数据太多&#xff0c;手动导入不显示&#xff0c;于是分析了json格式后果断通过脚本完成 【推荐】 《【MQTT】Esp32数据上传采集&#xff1a;最…

栈和队列的概念和实现

栈和队列的概念和实现 一.栈二.队列一些题目 一.栈 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作&#xff0c;进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底&#xff0c;栈中的数据元素遵守后进先出LIFO&#x…

UG\NX二次开发 用程序修改“用户默认设置”

文章作者:里海 来源网站:《里海NX二次开发3000例专栏》 简介 可以用程序修改“用户默认设置”吗?下面是用代码修改“用户默认设置->基本环境->用户界面->操作记录->操作记录语言”的例子。 效果 代码 #include <uf_defs.h> #include <NXOpen/NXExcept…

angular 在vscode 下的hello world

Angulai 是google 公司开发的前端开发框架。Angular 使用 typescript 作为编程语言。typescript 是Javascript 的一个超集&#xff0c;提升了某些功能。本文介绍运行我的第一个angular 程序。 前面部分参考&#xff1a; Angular TypeScript Tutorial in Visual Studio Code 一…

Kafka-Kerberos票据刷新问题

线上kafka使用了 kerberos 认证&#xff0c;每隔24小时&#xff0c;票据过期&#xff0c;无法自动续期&#xff0c;出现消息发送失败问题。 从日志可以发现会有如下报错&#xff1a; 2023-09-14 17:48:47,144 [kafka-kerberos-refresh-thread-kafka/hdp-1HADOOP.COM] [] WARN …

gitee 远程仓库操作基础(二)

(1&#xff09;clone远端仓库,本地建立分支推送 (基于远程仓库版本库 本地建立分支开发新功能) git clone gitgitee.com:xxxxx/alsa_test.git git remote add origin gitgitee.com:xxxxx/alsa_test.git进入clone过后路径代码,查看本地分支,发现该项目远程仓库有很多分支 基于…

Spring Framework 学习笔记5:事务

Spring Framework 学习笔记5&#xff1a;事务 1.快速入门 1.1.准备工作 这里提供一个示例项目 transaction-demo&#xff0c;这个项目包含 Spring 框架、MyBatis 以及 JUnit。 对应的表结构见 bank.sql。 服务层有一个方法可以用于在不同的账户间进行转账&#xff1a; Se…

机器学习之单层神经网络的训练:增量规则(Delta Rule)

文章目录 权重的调整单层神经网络使用delta规则的训练过程 神经网络以权值的形式存储信息,根据给定的信息来修改权值的系统方法称为学习规则。由于训练是神经网络系统地存储信息的唯一途径&#xff0c;因此学习规则是神经网络研究中的一个重要组成部分 权重的调整 &#xff08…

【中秋国庆不断更】OpenHarmony多态样式stateStyles使用场景

Styles和Extend仅仅应用于静态页面的样式复用&#xff0c;stateStyles可以依据组件的内部状态的不同&#xff0c;快速设置不同样式。这就是我们本章要介绍的内容stateStyles&#xff08;又称为&#xff1a;多态样式&#xff09;。 概述 stateStyles是属性方法&#xff0c;可以根…

蓝桥等考Python组别十级003

第一部分&#xff1a;选择题 1、Python L10 &#xff08;15分&#xff09; 已知s Pencil&#xff0c;下列说法正确的是&#xff08; &#xff09;。 s[0]对应的字符是Ps[1]对应的字符是ns[-1]对应的字符是is[3]对应的字符是e 正确答案&#xff1a;A 2、Python L10 &am…