SpringBoot引入主盘探活定时任务

主盘探活通常是指检查存储设备(例如硬盘)是否可读写,但在Java中并没有直接针对硬件级别的磁盘探活API。然而,我们可以模拟一个场景,即检查某个目录或文件是否可以被Java程序正常读写,以此作为主盘活跃的一个间接判断依据。
在这里插入图片描述

[Ref] What is @Scheduled does?
在这里插入图片描述

第1步:创建定时任务服务类
构造一个探活线程池,执行探活线程任务

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@Component
public class StorageHealthyCheckTask {
   
    private static volatile AtomicBoolean isActive = new AtomicBoolean(true);

    @Value("${storage.path}")
    private String storagePath;
    @Value("${storage.needCheck}")
    private boolean needCheck;

    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
            3, 3, 
            5, TimeUnit.SECONDS, 
            new LinkedBlockingQueue<>(1), 
            new ThreadFactoryBuilder().setNameFormat("探活检查-%d").setDaemon(true).build(), 
            new ThreadPoolExecutor.DiscardPolicy());

    @Scheduled(cron = "0/5 * * * * ?") // 每分钟执行一次
    private void storageHealthyCheck() {
   
        log.info("{}线程 调用:storageHealthyCheck start", Thread.currentThread().getName());
        if (!needCheck) {
   
            log.info("no need check");
            return;
        }

        // true表示正常状态,则已知探活
        if (BooleanUtils.isTrue(isActive.get())) {
   
            check(Paths.get(storagePath), isActive);
        } else {
   
            // false表示失败,则报错
            log.error("isActive:{}", false);
        }

        log.info("{}线程 调用:storageHealthyCheck end \n", Thread.currentThread().getName());
    }

    private void check(Path path, AtomicBoolean flag) {
   
        try {
   
            Future<Boolean> future = executor.submit(() -> {
   
                try {
   
                    log.info("{}线程 测试isReadable", Thread.currentThread().getName());

                    // true表示有读权限,false表没读权限,超时中断就会异常退出
                    return Files.isReadable(path);
                } finally {
   
                    // 只要路径存在且可读, 就可以认为存储服务是健康的
                    flag.set(true);
                }
            });

            Boolean res = future.get(2, TimeUnit.SECONDS);
            log.info("{}线程 isReadable结果: {}", Thread.currentThread().getName(), res);
        } catch (InterruptedException e) {
   
            Thread.currentThread().interrupt(); // 重新设置中断状态
            log.error("Thread was interrupted while waiting for the check task to complete.", e);
            flag.set(false);
        } catch (TimeoutException e) {
   
            log.error("Check task did not complete within the timeout of 2 seconds.", e);
            flag.set(false);
        } catch (CancellationException e) {
   
            log.error("Check task was cancelled before it could complete.", e);
            flag.set(false);
        } catch (ExecutionException e) {
   
            log.error("An error occurred while executing the check task", e);
            flag.set(false);
        }
    }
}

第2步:在application.yaml中添加定时任务相关的属性
配置支持探活开关,以主盘路径

storage:
  path: C:\Users\zhang\Desktop\test
  needCheck: true

第3步:添加@EnableScheduling注解来启用定时任务调度功能

@SpringBootApplication
@MapperScan("com.zhangziwa.practisesvr.mapper")
@EnableScheduling
public class PractisesvrApplication {
   

    public static void main(String[] args) {
   
        SpringApplication.run(PractisesvrApplication.class, args);
    }
}

第4步:单独记录探活日志

<RollingFile name="storage_check"
             fileName="${LOG_HOME}/storage_check.log"
             filePattern="${LOG_HOME}/storage_check_%d{yyyy-MM-dd-HH}_%i.log.gz"
             createOnDemand="true">
    <PatternLayout pattern="${LOG_PATTERN}"/>
    <Policies>
        <SizeBasedTriggeringPolicy size="1M"/>
    </Policies>
    <DefaultRolloverStrategy fileIndex="nomax">
        <Delete basePath="${LOG_HOME}" maxDepth="2">
            <IfFileName glob="*.log.gz">
                <IfAny>
                    <IfAccumulatedFileSize exceeds="10M"/>
                    <IfAccumulatedFileCount exceeds="100"/>
                    <IfLastModified age="30d"/>
                </IfAny>
            </IfFileName>
        </Delete>
    </DefaultRolloverStrategy>
</RollingFile>

<logger name="com.zhangziwa.practisesvr.utils.task.StorageHealthyCheckTask" level="info" additivity="false">
    <AppenderRef ref="CONSOLE"/>
    <AppenderRef ref="storage_check"/>
</logger>

第5步:起服务验证
在这里插入图片描述
在这里插入图片描述

相关推荐

  1. springboot定时任务

    2024-01-29 01:10:02       64 阅读
  2. SpringBoot 实现定时任务

    2024-01-29 01:10:02       59 阅读
  3. SpringBoot定时任务

    2024-01-29 01:10:02       43 阅读
  4. SpringBoot整合定时任务

    2024-01-29 01:10:02       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-29 01:10:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-29 01:10:02       101 阅读
  3. 在Django里面运行非项目文件

    2024-01-29 01:10:02       82 阅读
  4. Python语言-面向对象

    2024-01-29 01:10:02       91 阅读

热门阅读

  1. 第九章 SQL Search REST 接口

    2024-01-29 01:10:02       47 阅读
  2. Android 自定义builder对话框

    2024-01-29 01:10:02       62 阅读
  3. 如何把word檔案自動化

    2024-01-29 01:10:02       52 阅读
  4. 机器学习面试题总结60-99

    2024-01-29 01:10:02       54 阅读
  5. 我来啦,我又来啦

    2024-01-29 01:10:02       43 阅读
  6. 按键控制LED灯

    2024-01-29 01:10:02       46 阅读
  7. HTML — 框架 iframe

    2024-01-29 01:10:02       60 阅读
  8. 事件的学习

    2024-01-29 01:10:02       45 阅读
  9. lc31 下一个排列

    2024-01-29 01:10:02       52 阅读