用shell脚本自己一个秒级定时任务

 更新时间:2024年12月13日 09:52:24   作者:半桶水专家  
这篇文章主要为大家详细介绍了如何使用Shell脚本实现一个定时任务管理工具,可以每秒执行一次,并保证任务异步、非阻塞执行,需要的可以参考下

设计一个定时任务管理工具,使用 Shell 脚本实现,核心目标是实现每秒执行一次,并保证任务异步、非阻塞执行。以下是实现的详细设计:

工具功能

任务注册:支持注册新任务。

任务删除:支持删除已有任务。

任务执行:每秒执行一次任务。

异步非阻塞:任务在独立的进程中执行,不影响主进程。

日志记录:任务执行结果记录到日志文件中。

脚本设计

#!/bin/bash
 
# 配置文件和日志文件路径
CONFIG_FILE="./tasks.conf"
LOG_FILE="./tasks.log"
PID_FILE="./scheduler.pid"
RELOAD_SIGNAL_FILE="./reload.signal"
 
# 初始化配置文件和信号文件
if [ ! -f "$CONFIG_FILE" ]; then
    touch "$CONFIG_FILE"
fi
if [ -f "$RELOAD_SIGNAL_FILE" ]; then
    rm -f "$RELOAD_SIGNAL_FILE"
fi
 
# 任务状态跟踪表
declare -A LAST_EXECUTION_TIMES
 
# 定时调度器
scheduler() {
    echo $$ > "$PID_FILE"
    echo "调度器启动,PID: $$"
 
    while true; do
        # 检查是否需要重新加载配置
        if [ -f "$RELOAD_SIGNAL_FILE" ]; then
            echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] 重新加载配置" >> "$LOG_FILE"
            LAST_EXECUTION_TIMES=()  # 清空上次执行记录
            rm -f "$RELOAD_SIGNAL_FILE"
        fi
 
        # 当前时间戳
        local current_time=$(date +%s)
 
        # 动态加载配置文件并执行任务
        while IFS="=" read -r task_name interval command; do
            [ -z "$task_name" ] || [ -z "$interval" ] || [ -z "$command" ] && continue
 
            # 获取上次执行时间,如果没有记录,默认为0
            local last_exec_time=${LAST_EXECUTION_TIMES[$task_name]:-0}
 
            # 判断是否到达执行间隔
            if (( current_time - last_exec_time >= interval )); then
                (   #安装任务名记录任务执行情况
                    local TASK_LOG_FILE="$task_name/$(date '+%Y-%m-%d').log"
                    if [ ! -d "$(dirname "$TASK_LOG_FILE")" ]; then
                        mkdir -p "$(dirname "$TASK_LOG_FILE")"
                    fi
                    echo "$(date +'%H:%M:%S')执行start" >> "$TASK_LOG_FILE"
                    eval "$command" >> "$TASK_LOG_FILE" 2>&1
                    echo "end" >> "$TASK_LOG_FILE"
                ) &
                LAST_EXECUTION_TIMES[$task_name]=$current_time  # 更新任务的最后执行时间
            fi
        done < "$CONFIG_FILE"
 
        # 等待 1 秒
        sleep 1
    done
}
 
# 停止调度器
stop_scheduler() {
    if [ -f "$PID_FILE" ]; then
        local pid
        pid=$(cat "$PID_FILE")
        kill "$pid" && rm -f "$PID_FILE"
        echo "调度器已停止"
    else
        echo "调度器未运行"
    fi
}
 
# 添加任务
add_task() {
    local task_name="$1"
    local interval="$2"
    local command="$3"
    if grep -q "^$task_name=" "$CONFIG_FILE"; then
        echo "任务 '$task_name' 已存在"
        return 1
    fi
    echo "$task_name=$interval=$command" >> "$CONFIG_FILE"
    echo "任务 '$task_name' 添加成功"
}
 
# 删除任务
remove_task() {
    local task_name="$1"
    if ! grep -q "^$task_name=" "$CONFIG_FILE"; then
        echo "任务 '$task_name' 不存在"
        return 1
    fi
    sed -i "/^$task_name=/d" "$CONFIG_FILE"
    echo "任务 '$task_name' 已删除"
}
 
# 重新加载配置
reload_scheduler() {
    if [ ! -f "$PID_FILE" ]; then
        echo "调度器未运行,无法重新加载配置"
        return 1
    fi
    touch "$RELOAD_SIGNAL_FILE"
    echo "配置重新加载信号已发送"
}
 
# 显示帮助
show_help() {
    echo "用法: $0 [命令] [参数]"
    echo "命令:"
    echo "  start             启动调度器"
    echo "  stop              停止调度器"
    echo "  reload            重新加载配置文件"
    echo "  add 任务名 间隔秒数 命令  添加任务到配置文件"
    echo "  remove 任务名      从配置文件中删除任务"
    echo "  help              显示帮助"
}
 
# 主逻辑
case "$1" in
    start)
        scheduler
        ;;
    stop)
        stop_scheduler
        ;;
    reload)
        reload_scheduler
        ;;
    add)
        add_task "$2" "$3" "$4"
        ;;
    remove)
        remove_task "$2"
        ;;
    help|*)
        show_help
        ;;
esac

配置文件格式

使用 tasks.conf 文件存储任务配置,每行一个任务,格式为:

任务名=间隔秒数=命令

例如:

task1=5=echo '每5秒运行一次'
task2=30=date
task3=10=sleep 2 && echo '任务完成'

启动调度器

./scheduler.sh start

添加任务

./scheduler.sh add "task1" 5 "echo 'Hello, every 5 seconds!'"

删除任务

./scheduler.sh remove "task1"

重新加载配置

./scheduler.sh reload

停止调度器

./scheduler.sh stop

同时支持手动修改配置文件修改任务

实现原理

任务间隔控制:使用关联数组 LAST_EXECUTION_TIMES 记录每个任务的最后执行时间。

动态间隔判断:在每秒循环中,检查当前时间与任务的最后执行时间的差值是否达到设定的间隔秒数。

动态配置管理:配置文件支持实时修改,结合 reload 功能可立即生效。

异步执行:每个任务独立进程执行,不阻塞其他任务。

优点

支持自定义间隔:满足不同任务执行频率的需求。

动态加载:无需重启即可更新任务配置。

高可扩展性:可根据需要进一步优化,如添加任务优先级或日志清理功能。

为定时器创建 systemd 服务

创建一个新的 systemd 服务文件:你可以将服务单元文件放在 /etc/systemd/system/ 目录下。假设我们创建一个名为 task-scheduler.service 的服务。

sudo nano /etc/systemd/system/task-scheduler.service

编辑服务单元文件:以下是 task-scheduler.service 的内容模板。你可以根据需要修改。

[Unit]
Description=Task Scheduler Service
After=network.target
 
[Service]
Type=simple
User=root
ExecStart=/path/to/your/scheduler.sh start
ExecReload=/path/to/your/scheduler.sh reload
ExecStop=/path/to/your/scheduler.sh stop
WorkingDirectory=/path/to/working/directory
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=task-scheduler
 
[Install]
WantedBy=multi-user.target

重新加载 systemd 配置:让 systemd 识别新的服务单元文件。

sudo systemctl daemon-reload

启用服务:设置服务在系统启动时自动启动。

sudo systemctl enable task-scheduler.service

开机启动服务:立即启动任务调度器服务。

sudo systemctl start task-scheduler.service

检查服务状态:确认服务是否正常启动。

sudo systemctl status task-scheduler.service

停止服务:

sudo systemctl stop task-scheduler.service

重新加载配置(如果你修改了配置文件或脚本):

sudo systemctl reload task-scheduler.service

可以通过 journalctl 命令查看服务日志,以便调试:

sudo journalctl -u task-scheduler.service

到此这篇关于用shell脚本自己一个秒级定时任务的文章就介绍到这了,更多相关shell定时任务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • linux获取系统启动时间示例详解

    linux获取系统启动时间示例详解

    这篇文章主要介绍了linux获取系统启动时间的示例,需要的朋友可以参考下
    2014-02-02
  • 使用Shell遍历目录及其子目录中的所有文件方法

    使用Shell遍历目录及其子目录中的所有文件方法

    今天小编就为大家分享一篇使用Shell遍历目录及其子目录中的所有文件方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-06-06
  • Linux shell中改文件名的方法总结

    Linux shell中改文件名的方法总结

    这篇文章主要给大家介绍了关于Linux shell中改文件名的方法,在Shell中有多种方法可以来修改文件名,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-06-06
  • shell linux中如何用shell写一个占用CPU的脚本

    shell linux中如何用shell写一个占用CPU的脚本

    本文主要介绍了shell linux中如何用shell写一个占用CPU的脚本,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Linux shell字符串截取、替换、删除以及trim代码示例

    Linux shell字符串截取、替换、删除以及trim代码示例

    在Shell编程中,截取、替换、删除字符串是非常常见的操作,这篇文章主要给大家介绍了关于Linux shell字符串截取、替换、删除以及trim的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • Shell双引号和单引号有哪些不同

    Shell双引号和单引号有哪些不同

    这篇文章主要介绍了Shell双引号和单引号有哪些不同,帮助大家区分shell双引号和单引号,感兴趣的朋友可以了解下
    2020-08-08
  • shell脚本4种执行方式

    shell脚本4种执行方式

    Linux中shell脚本的执行通常有4种方式,分别为工作目录执行,绝对路径执行,sh执行,shell环境执行。这篇文章主要介绍了shell脚本4种执行方式 ,需要的朋友可以参考下
    2019-05-05
  • Shell 实现多任务并发的示例代码

    Shell 实现多任务并发的示例代码

    本文主要介绍了Shell 实现多任务并发的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • linux网络编程用到的网络函数详解用和使用示例

    linux网络编程用到的网络函数详解用和使用示例

    本文对linux网络编程用到的网络函数做了简单介绍,提供了使用示例供大家参考
    2013-11-11
  • 使用shell读取ini文件方法步骤

    使用shell读取ini文件方法步骤

    本文主要介绍了使用shell读取ini文件方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06

最新评论