How to add a more robust PID file management mechanism to the AnQiCMS startup script?
As a senior security CMS website operation personnel, I know that the stability and reliability of website services are the foundation of successful content operation.AnQiCMS with its efficient characteristics and concise architecture in Go language provides us with a solid foundation, but ensuring the robustness of its startup and shutdown in actual deployment, especially process management, is the key link that needs to be refined.
Today's article, we will delve into how to introduce a more robust PID (Process ID) file management mechanism in the AnQiCMS startup script to avoid common issues such as process zombies, port occupation, or service interruption, ensuring that our AnQiCMS site always runs stably.
Why do we need a more robust PID file management?
In the deployment practice of AnQiCMS, we may encounter such scenarios: the AnQiCMS service crashes unexpectedly, but the system mistakenly thinks it is still running; or when trying to start a new instance, a port conflict occurs due to the old process not being fully terminated. The existing startup scripts such asstart.shpass throughps -ef | grepTo judge whether the process exists) although simple, it has certain limitations in complex or abnormal situations.
For example,grepThe command may misjudge: When other irrelevant process names or parameters accidentally contain "anqicms", it may incorrectly report that AnQiCMS is running, thereby preventing the startup of a new instance. Moreover, if the service crashes,grepIt may not be recognized as a "zombie process" or a terminated but uncleaned process, which may cause PID files to linger or be inaccurate, causing trouble for subsequent operations.
The PID file (Process ID file) is created to solve these problems.It is a simple text file used to store the unique identifier (PID) of a specific running process.By the PID file, we can accurately trace and manage individual service instances, ensuring that each operation is based on the accurate process status.
Review of AnQiCMS existing start/stop scripts
Let's review the AnQiCMS providedstart.shandstop.shSimplified version of the scripts:
start.sh:
BINNAME=anqicms
BINPATH=/www/wwwroot/anqicms
exists=`ps -ef | grep '\<anqicms\>' |grep -v grep |wc -l`
if [ $exists -eq 0 ]; then
# ... 启动AnQiCMS进程 ...
cd $BINPATH && nohup $BINPATH/$BINNAME >> $BINPATH/running.log 2>&1 &
fi
This script mainly usesgrepCheck the process count, if it is 0, then start.
stop.sh:
BINNAME=anqicms
BINPATH="$( cd "$( dirname "$0" )" && pwd )"
exists=`ps -ef | grep '\<anqicms\>' |grep -v grep |awk '{printf $2}'`
if [ $exists -eq 0 ]; then
# ... 未运行 ...
else
kill -9 $exists # 直接强制终止
fi
Stopping the script also depends on it.grepGet the PID and use it.kill -9Force termination. This method may cause the AnQiCMS service to be unable to perform necessary resource cleanup, such as closing database connections, saving temporary data, and so on.
Introduce a robust PID file management mechanism
To overcome the aforementioned limitations, we willstart.shandstop.shModify, introduce the creation, verification, use, and cleanup of PID files.
The core idea:
- At startupCheck the PID file. If the file exists, read the PID and verify whether the process is really running.If running, refuse to start; if not running, treat as an old PID file and delete.Then, start AnQiCMS and write its PID to a new PID file.
- At shutdown: Check the PID file. If the file exists, read the PID and verify whether the process is running.If running, attempt to send SIGHUP or SIGTERM signals (allowing graceful shutdown), wait for a while;If it has not stopped yet, send SIGKILL (force termination).Finally, delete the PID file regardless of success or failure.
1. Define the PID file path
Firstly, we need to specify a unique PID file path for each instance of AnQiCMS. Usually, we will place the PID file in the root directory of the AnQiCMS installation or a dedicatedrundirectory.
PID_FILE="$BINPATH/anqicms.pid"
2. Transform the startup script (start.sh)
of this versionstart.shwill be more intelligent, capable of handling various situations such as the existence of PID files, processes still running, or outdated PID files.
#!/bin/bash
### check and start AnqiCMS with robust PID management
# author fesion
# the bin name is anqicms
BINNAME=anqicms
BINPATH=/www/wwwroot/anqicms # 请根据实际路径修改
LOG_FILE="$BINPATH/running.log"
CHECK_LOG="$BINPATH/check.log"
PID_FILE="$BINPATH/$BINNAME.pid"
echo "$(date +'%Y%m%d %H:%M:%S') --- AnQiCMS startup script initiated ---" >> "$CHECK_LOG"
# 函数:检查PID是否正在运行
is_running() {
local pid=$1
if [ -z "$pid" ]; then
return 1
fi
# kill -0 PID 不发送任何信号,但会检查是否存在该进程ID的进程
kill -0 "$pid" > /dev/null 2>&1
return $?
}
# 检查PID文件是否存在
if [ -f "$PID_FILE" ]; then
CURRENT_PID=$(cat "$PID_FILE")
echo "$(date +'%Y%m%d %H:%M:%S') PID file found: $PID_FILE, PID: $CURRENT_PID" >> "$CHECK_LOG"
if is_running "$CURRENT_PID"; then
echo "$(date +'%Y%m%d %H:%M:%S') AnQiCMS is already running with PID $CURRENT_PID. Exiting." >> "$CHECK_LOG"
echo "AnQiCMS is already running with PID $CURRENT_PID. Exiting."
exit 1 # 服务已经在运行,退出
else
echo "$(date +'%Y%m%d %H:%M:%S') Stale PID file found. Removing $PID_FILE." >> "$CHECK_LOG"
rm -f "$PID_FILE" # PID文件存在但进程已死,删除旧文件
fi
else
echo "$(date +'%Y%m%d %H:%M:%S') PID file not found. Proceeding with startup." >> "$CHECK_LOG"
fi
# 启动AnQiCMS进程
echo "$(date +'%Y%m%d %H:%M:%S') Starting AnQiCMS..." >> "$CHECK_LOG"
cd "$BINPATH" && nohup "$BINPATH/$BINNAME" >> "$LOG_FILE" 2>&1 &
NEW_PID=$! # 获取后台启动进程的PID
echo "$NEW_PID" > "$PID_FILE" # 将PID写入文件
if is_running "$NEW_PID"; then
echo "$(date +'%Y%m%d %H:%M:%S') AnQiCMS started successfully with PID $NEW_PID." >> "$CHECK_LOG"
echo "AnQiCMS started successfully with PID $NEW_PID."
else
echo "$(date +'%Y%m%d %H:%M:%S') Failed to start AnQiCMS." >> "$CHECK_LOG"
echo "Failed to start AnQiCMS."
rm -f "$PID_FILE" # 启动失败,清理PID文件
exit 1
fi
Description:
is_runningfunction usagekill -0Check if the process exists, this isgrepmore accurate.- The script will first check the PID file and judge whether the service is running according to the PID in the file.
- If the PID file exists but the corresponding process has died, the script will automatically clean up this 'stale' PID file.
- After successful startup, the new process PID will be written.
anqicms.pidfile. - The process failed but the PID file will also be cleaned up.
3. Refactor the stop script (stop.sh)
of this versionstop.shIt will try to shut down gracefully first, and only terminate forcibly after timeout.
`bash #!/bin/bash
stop AnqiCMS with robust PID management
author fesion
the bin name is anqicms
BINNAME=anqicms BINPATH=\( ( cd " )( dirname " )(0" )" && pwd )" # Get the directory of the script CHECK_LOG="\)BINPATH/check.log PID_FILE=(BINPATH/)BINNAME.pid GRACEFUL_TIMEOUT=10 # Graceful shutdown wait time
echo \((date +'%Y%m%d %H:%M:%S') --- AnQiCMS stop script initiated ---" >> "\)CHECK_LOG
Function: Check if the PID is running
is_running() {
local pid=$1
if [ -z "$pid" ]; then
return 1
fi
kill -0 "$pid" > /dev/null 2>&1
return $?
}
Check if the PID file exists
if [ -f “$PID_FILE” ]; then
TARGET_PID=$(cat "$PID_FILE")
echo "$(date +'%Y%m%d %H:%M:%S') PID file found: $PID_FILE, PID: $TARGET_PID" >> "$CHECK_LOG"
if is_running "$TARGET_PID"; then
echo "$(date +'%Y%m%d %H:%M:%S') Attempting graceful shutdown for AnQiCMS (PID: $TARGET_PID)..." >> "$CHECK_LOG"
kill "$TARGET_PID" # 发送SIGTERM信号 (15),尝试优雅关闭
# 等待进程优雅关闭
for i in $(seq 1 $GRACEFUL_TIMEOUT); do
if ! is_running "$TARGET_PID"; then
echo "$(date +'%Y%m%d %H:%M:%S') AnQiCMS (PID: $TARGET_PID) stopped gracefully." >> "$CHECK_LOG"
break
fi
sleep 1
done
if is_running "$TARGET_PID"; then
echo "$(date +'%Y%m%d %H:%M:%S') AnQiCMS (PID: $TARGET_PID) did not stop gracefully within $GRACEFUL_TIMEOUT seconds. Forcing shutdown..." >> "$CHECK_LOG"
kill -9 "$TARGET_PID" # 发送SIGKILL信号 (9),强制终止
sleep 1 # 确保进程有时间被系统终止
if ! is_running "$TARGET_PID"; then
echo "$(date +'%Y%m