用shell腳本自己一個秒級定時任務(wù)
設(shè)計一個定時任務(wù)管理工具,使用 Shell 腳本實(shí)現(xiàn),核心目標(biāo)是實(shí)現(xiàn)每秒執(zhí)行一次,并保證任務(wù)異步、非阻塞執(zhí)行。以下是實(shí)現(xiàn)的詳細(xì)設(shè)計:
工具功能
任務(wù)注冊:支持注冊新任務(wù)。
任務(wù)刪除:支持刪除已有任務(wù)。
任務(wù)執(zhí)行:每秒執(zhí)行一次任務(wù)。
異步非阻塞:任務(wù)在獨(dú)立的進(jìn)程中執(zhí)行,不影響主進(jìn)程。
日志記錄:任務(wù)執(zhí)行結(jié)果記錄到日志文件中。
腳本設(shè)計
#!/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 # 任務(wù)狀態(tài)跟蹤表 declare -A LAST_EXECUTION_TIMES # 定時調(diào)度器 scheduler() { echo $$ > "$PID_FILE" echo "調(diào)度器啟動,PID: $$" while true; do # 檢查是否需要重新加載配置 if [ -f "$RELOAD_SIGNAL_FILE" ]; then echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] 重新加載配置" >> "$LOG_FILE" LAST_EXECUTION_TIMES=() # 清空上次執(zhí)行記錄 rm -f "$RELOAD_SIGNAL_FILE" fi # 當(dāng)前時間戳 local current_time=$(date +%s) # 動態(tài)加載配置文件并執(zhí)行任務(wù) while IFS="=" read -r task_name interval command; do [ -z "$task_name" ] || [ -z "$interval" ] || [ -z "$command" ] && continue # 獲取上次執(zhí)行時間,如果沒有記錄,默認(rèn)為0 local last_exec_time=${LAST_EXECUTION_TIMES[$task_name]:-0} # 判斷是否到達(dá)執(zhí)行間隔 if (( current_time - last_exec_time >= interval )); then ( #安裝任務(wù)名記錄任務(wù)執(zhí)行情況 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')執(zhí)行start" >> "$TASK_LOG_FILE" eval "$command" >> "$TASK_LOG_FILE" 2>&1 echo "end" >> "$TASK_LOG_FILE" ) & LAST_EXECUTION_TIMES[$task_name]=$current_time # 更新任務(wù)的最后執(zhí)行時間 fi done < "$CONFIG_FILE" # 等待 1 秒 sleep 1 done } # 停止調(diào)度器 stop_scheduler() { if [ -f "$PID_FILE" ]; then local pid pid=$(cat "$PID_FILE") kill "$pid" && rm -f "$PID_FILE" echo "調(diào)度器已停止" else echo "調(diào)度器未運(yùn)行" fi } # 添加任務(wù) add_task() { local task_name="$1" local interval="$2" local command="$3" if grep -q "^$task_name=" "$CONFIG_FILE"; then echo "任務(wù) '$task_name' 已存在" return 1 fi echo "$task_name=$interval=$command" >> "$CONFIG_FILE" echo "任務(wù) '$task_name' 添加成功" } # 刪除任務(wù) remove_task() { local task_name="$1" if ! grep -q "^$task_name=" "$CONFIG_FILE"; then echo "任務(wù) '$task_name' 不存在" return 1 fi sed -i "/^$task_name=/d" "$CONFIG_FILE" echo "任務(wù) '$task_name' 已刪除" } # 重新加載配置 reload_scheduler() { if [ ! -f "$PID_FILE" ]; then echo "調(diào)度器未運(yùn)行,無法重新加載配置" return 1 fi touch "$RELOAD_SIGNAL_FILE" echo "配置重新加載信號已發(fā)送" } # 顯示幫助 show_help() { echo "用法: $0 [命令] [參數(shù)]" echo "命令:" echo " start 啟動調(diào)度器" echo " stop 停止調(diào)度器" echo " reload 重新加載配置文件" echo " add 任務(wù)名 間隔秒數(shù) 命令 添加任務(wù)到配置文件" echo " remove 任務(wù)名 從配置文件中刪除任務(wù)" 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 文件存儲任務(wù)配置,每行一個任務(wù),格式為:
任務(wù)名=間隔秒數(shù)=命令
例如:
task1=5=echo '每5秒運(yùn)行一次' task2=30=date task3=10=sleep 2 && echo '任務(wù)完成'
啟動調(diào)度器
./scheduler.sh start
添加任務(wù)
./scheduler.sh add "task1" 5 "echo 'Hello, every 5 seconds!'"
刪除任務(wù)
./scheduler.sh remove "task1"
重新加載配置
./scheduler.sh reload
停止調(diào)度器
./scheduler.sh stop
同時支持手動修改配置文件修改任務(wù)
實(shí)現(xiàn)原理
任務(wù)間隔控制:使用關(guān)聯(lián)數(shù)組 LAST_EXECUTION_TIMES 記錄每個任務(wù)的最后執(zhí)行時間。
動態(tài)間隔判斷:在每秒循環(huán)中,檢查當(dāng)前時間與任務(wù)的最后執(zhí)行時間的差值是否達(dá)到設(shè)定的間隔秒數(shù)。
動態(tài)配置管理:配置文件支持實(shí)時修改,結(jié)合 reload 功能可立即生效。
異步執(zhí)行:每個任務(wù)獨(dú)立進(jìn)程執(zhí)行,不阻塞其他任務(wù)。
優(yōu)點(diǎn)
支持自定義間隔:滿足不同任務(wù)執(zhí)行頻率的需求。
動態(tài)加載:無需重啟即可更新任務(wù)配置。
高可擴(kuò)展性:可根據(jù)需要進(jìn)一步優(yōu)化,如添加任務(wù)優(yōu)先級或日志清理功能。
為定時器創(chuàng)建 systemd 服務(wù)
創(chuàng)建一個新的 systemd 服務(wù)文件:你可以將服務(wù)單元文件放在 /etc/systemd/system/ 目錄下。假設(shè)我們創(chuàng)建一個名為 task-scheduler.service 的服務(wù)。
sudo nano /etc/systemd/system/task-scheduler.service
編輯服務(wù)單元文件:以下是 task-scheduler.service 的內(nèi)容模板。你可以根據(jù)需要修改。
[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 識別新的服務(wù)單元文件。
sudo systemctl daemon-reload
啟用服務(wù):設(shè)置服務(wù)在系統(tǒng)啟動時自動啟動。
sudo systemctl enable task-scheduler.service
開機(jī)啟動服務(wù):立即啟動任務(wù)調(diào)度器服務(wù)。
sudo systemctl start task-scheduler.service
檢查服務(wù)狀態(tài):確認(rèn)服務(wù)是否正常啟動。
sudo systemctl status task-scheduler.service
停止服務(wù):
sudo systemctl stop task-scheduler.service
重新加載配置(如果你修改了配置文件或腳本):
sudo systemctl reload task-scheduler.service
可以通過 journalctl 命令查看服務(wù)日志,以便調(diào)試:
sudo journalctl -u task-scheduler.service
到此這篇關(guān)于用shell腳本自己一個秒級定時任務(wù)的文章就介紹到這了,更多相關(guān)shell定時任務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
shell linux中如何用shell寫一個占用CPU的腳本
本文主要介紹了shell linux中如何用shell寫一個占用CPU的腳本,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09Linux?shell字符串截取、替換、刪除以及trim代碼示例
在Shell編程中,截取、替換、刪除字符串是非常常見的操作,這篇文章主要給大家介紹了關(guān)于Linux?shell字符串截取、替換、刪除以及trim的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03Shell 實(shí)現(xiàn)多任務(wù)并發(fā)的示例代碼
本文主要介紹了Shell 實(shí)現(xiàn)多任務(wù)并發(fā)的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06linux網(wǎng)絡(luò)編程用到的網(wǎng)絡(luò)函數(shù)詳解用和使用示例
本文對linux網(wǎng)絡(luò)編程用到的網(wǎng)絡(luò)函數(shù)做了簡單介紹,提供了使用示例供大家參考2013-11-11