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步:起服务验证
在这里插入图片描述
在这里插入图片描述

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值