mirror of
https://github.com/rnvm9wjdtj-bot/myaps_api.git
synced 2026-06-02 05:54:40 +00:00
增加服务守护功能
This commit is contained in:
@@ -160,7 +160,6 @@ def refresh_stock(dbs: str=MYAPS_DB_SET):
|
||||
ApsHelpers.refresh_supply(stock_data_total.to_dict(orient='records'), dbs=dbs)
|
||||
|
||||
|
||||
|
||||
def push_pr(period: int = 30, groupdates: List[str] | str = None):
|
||||
if groupdates:
|
||||
if isinstance(groupdates, list):
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
$OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# Set input encoding to UTF-8
|
||||
[System.Text.Encoding]::Default = [System.Text.Encoding]::UTF8
|
||||
|
||||
# Get project root directory
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$ProjectRoot = Split-Path -Parent $ScriptDir
|
||||
@@ -43,10 +46,10 @@ function Get-RecentLogs {
|
||||
$recentLogs = @()
|
||||
|
||||
try {
|
||||
Get-Content $LogFile | ForEach-Object {
|
||||
Get-Content $LogFile -Encoding UTF8 | ForEach-Object {
|
||||
# Try to extract timestamp from log line
|
||||
$line = $_
|
||||
if ($line -match '^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})') {
|
||||
if ($line -match '^({4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})') {
|
||||
$logTime = [datetime]::ParseExact($matches[1], 'yyyy-MM-dd HH:mm:ss', $null)
|
||||
if ($logTime -ge $24HoursAgo) {
|
||||
$recentLogs += $line
|
||||
@@ -60,7 +63,7 @@ function Get-RecentLogs {
|
||||
}
|
||||
} catch {
|
||||
# If parsing fails, return all logs
|
||||
$recentLogs = Get-Content $LogFile
|
||||
$recentLogs = Get-Content $LogFile -Encoding UTF8
|
||||
}
|
||||
|
||||
return $recentLogs
|
||||
@@ -94,13 +97,13 @@ try {
|
||||
$job = Start-Job -ScriptBlock {
|
||||
param($File)
|
||||
if (Test-Path $File) {
|
||||
Get-Content $File -Tail 0 -Wait
|
||||
Get-Content $File -Encoding UTF8 -Tail 0 -Wait
|
||||
} else {
|
||||
# Wait for file to be created
|
||||
while (-not (Test-Path $File)) {
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
Get-Content $File -Tail 0 -Wait
|
||||
Get-Content $File -Encoding UTF8 -Tail 0 -Wait
|
||||
}
|
||||
} -ArgumentList $AppLogFile
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
param (
|
||||
[string]$ServiceName = "",
|
||||
[string]$LogDir = "",
|
||||
[string]$EmailEnabled = "false",
|
||||
[string]$EmailTo = "",
|
||||
[string]$EmailFrom = "",
|
||||
[string]$SmtpServer = "",
|
||||
[int]$SmtpPort = 587,
|
||||
[string]$SmtpUser = "",
|
||||
[string]$SmtpPassword = "",
|
||||
[bool]$SystemNotification = $true,
|
||||
[bool]$AutoRestart = $true,
|
||||
[string]$EnvFile = ""
|
||||
)
|
||||
|
||||
# Calculate project root (parent directory of scripts)
|
||||
$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$projectRoot = Split-Path -Parent $scriptPath
|
||||
|
||||
# Set default EnvFile if not provided
|
||||
if ([string]::IsNullOrEmpty($EnvFile)) {
|
||||
$EnvFile = Join-Path $projectRoot ".env"
|
||||
}
|
||||
|
||||
# Set default LogDir if not provided
|
||||
if ([string]::IsNullOrEmpty($LogDir)) {
|
||||
$LogDir = Join-Path $projectRoot "logs"
|
||||
}
|
||||
|
||||
function Read-EnvFile {
|
||||
param (
|
||||
[string]$EnvFilePath
|
||||
)
|
||||
|
||||
if (-not (Test-Path $EnvFilePath)) {
|
||||
Write-Log "Environment file not found: $EnvFilePath" -Level "WARN"
|
||||
return @{}
|
||||
}
|
||||
|
||||
try {
|
||||
$envContent = Get-Content $EnvFilePath -Raw
|
||||
$envVariables = @{}
|
||||
|
||||
$lines = $envContent -split "`n"
|
||||
foreach ($line in $lines) {
|
||||
$line = $line.Trim()
|
||||
if ($line -and $line -notlike "#*" -and $line -match "=") {
|
||||
$key, $value = $line -split "=", 2
|
||||
$key = $key.Trim()
|
||||
$value = $value.Trim()
|
||||
$envVariables[$key] = $value
|
||||
}
|
||||
}
|
||||
|
||||
return $envVariables
|
||||
} catch {
|
||||
Write-Log "Failed to read environment file: $_" -Level "ERROR"
|
||||
return @{}
|
||||
}
|
||||
}
|
||||
|
||||
# Read configuration from .env file
|
||||
if (Test-Path $EnvFile) {
|
||||
$envVariables = Read-EnvFile -EnvFilePath $EnvFile
|
||||
|
||||
# Service configuration
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_NAME")) { $ServiceName = $envVariables["SERVICE_DAEMON_NAME"] }
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_LOG_DIR")) { $LogDir = $envVariables["SERVICE_DAEMON_LOG_DIR"] }
|
||||
|
||||
# Email configuration
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_EMAIL_ENABLED")) { $EmailEnabled = $envVariables["SERVICE_DAEMON_EMAIL_ENABLED"].ToLower() }
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_EMAIL_TO")) {
|
||||
$emailToValue = $envVariables["SERVICE_DAEMON_EMAIL_TO"]
|
||||
if ($emailToValue -match ",") {
|
||||
$EmailTo = $emailToValue -split "," | ForEach-Object { $_.Trim() }
|
||||
} else {
|
||||
$EmailTo = $emailToValue
|
||||
}
|
||||
}
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_EMAIL_FROM")) { $EmailFrom = $envVariables["SERVICE_DAEMON_EMAIL_FROM"] }
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_SMTP_SERVER")) { $SmtpServer = $envVariables["SERVICE_DAEMON_SMTP_SERVER"] }
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_SMTP_PORT")) { $SmtpPort = [int]$envVariables["SERVICE_DAEMON_SMTP_PORT"] }
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_SMTP_USER")) { $SmtpUser = $envVariables["SERVICE_DAEMON_SMTP_USER"] }
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_SMTP_PASSWORD")) { $SmtpPassword = $envVariables["SERVICE_DAEMON_SMTP_PASSWORD"] }
|
||||
|
||||
# Notifications configuration
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_SYSTEM_NOTIFICATION")) {
|
||||
$SystemNotification = [bool]::Parse($envVariables["SERVICE_DAEMON_SYSTEM_NOTIFICATION"])
|
||||
}
|
||||
|
||||
# Recovery configuration
|
||||
if ($envVariables.ContainsKey("SERVICE_DAEMON_AUTO_RESTART")) {
|
||||
$AutoRestart = [bool]::Parse($envVariables["SERVICE_DAEMON_AUTO_RESTART"])
|
||||
}
|
||||
|
||||
Write-Log "Configuration loaded from .env file: $EnvFile" -Level "INFO"
|
||||
}
|
||||
|
||||
# Set default service name if not found
|
||||
if ([string]::IsNullOrEmpty($ServiceName)) {
|
||||
$ServiceName = "MyAPS_API"
|
||||
Write-Log "Using default service name: $ServiceName" -Level "INFO"
|
||||
}
|
||||
|
||||
$logFile = Join-Path $LogDir "service_daemon.log"
|
||||
$errorLogFile = Join-Path $LogDir "service_daemon_errors.log"
|
||||
|
||||
function Write-Log {
|
||||
param (
|
||||
[string]$Message,
|
||||
[string]$Level = "INFO"
|
||||
)
|
||||
|
||||
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
$logMessage = "[$timestamp] [$Level] $Message"
|
||||
|
||||
try {
|
||||
Add-Content -Path $logFile -Value $logMessage -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Output "Failed to write to log file: $_"
|
||||
}
|
||||
|
||||
if ($Level -eq "ERROR") {
|
||||
try {
|
||||
Add-Content -Path $errorLogFile -Value $logMessage -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Output "Failed to write to error log file: $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Send-EmailNotification {
|
||||
param (
|
||||
[string]$Subject,
|
||||
[string]$Body
|
||||
)
|
||||
|
||||
if ($EmailEnabled -ne "true") {
|
||||
Write-Log "Email notification disabled, skipping email send"
|
||||
return
|
||||
}
|
||||
|
||||
if (([string]::IsNullOrEmpty($EmailTo) -and $EmailTo -isnot [array]) -or [string]::IsNullOrEmpty($EmailFrom) -or [string]::IsNullOrEmpty($SmtpServer)) {
|
||||
Write-Log "Email configuration incomplete, skipping email send" -Level "WARN"
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
$securePassword = ConvertTo-SecureString $SmtpPassword -AsPlainText -Force
|
||||
$credential = New-Object System.Management.Automation.PSCredential ($SmtpUser, $securePassword)
|
||||
|
||||
Send-MailMessage -From $EmailFrom -To $EmailTo -Subject $Subject -Body $Body -SmtpServer $SmtpServer -Port $SmtpPort -Credential $credential -UseSsl -ErrorAction Stop
|
||||
|
||||
# Log the recipients
|
||||
if ($EmailTo -is [array]) {
|
||||
$recipients = $EmailTo -join ", "
|
||||
} else {
|
||||
$recipients = $EmailTo
|
||||
}
|
||||
Write-Log "Email notification sent successfully to $recipients: $Subject"
|
||||
} catch {
|
||||
Write-Log "Failed to send email notification: $_" -Level "ERROR"
|
||||
}
|
||||
}
|
||||
|
||||
function Send-SystemNotification {
|
||||
param (
|
||||
[string]$Title,
|
||||
[string]$Message
|
||||
)
|
||||
|
||||
if (-not $SystemNotification) {
|
||||
Write-Log "System notification disabled, skipping notification"
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
|
||||
$notifyIcon = New-Object System.Windows.Forms.NotifyIcon
|
||||
$notifyIcon.Icon = [System.Drawing.SystemIcons]::Warning
|
||||
$notifyIcon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Warning
|
||||
$notifyIcon.BalloonTipTitle = $Title
|
||||
$notifyIcon.BalloonTipText = $Message
|
||||
$notifyIcon.Visible = $true
|
||||
|
||||
$notifyIcon.ShowBalloonTip(10000)
|
||||
|
||||
Start-Sleep -Seconds 10
|
||||
$notifyIcon.Dispose()
|
||||
|
||||
Write-Log "System notification sent: $Title"
|
||||
} catch {
|
||||
Write-Log "Failed to send system notification: $_" -Level "ERROR"
|
||||
}
|
||||
}
|
||||
|
||||
function Check-ServiceStatus {
|
||||
Write-Log "Starting service status check for: $ServiceName"
|
||||
|
||||
try {
|
||||
$service = Get-Service -Name $ServiceName -ErrorAction Stop
|
||||
|
||||
if ($service.Status -eq "Running") {
|
||||
Write-Log "Service $ServiceName is running normally"
|
||||
return $true
|
||||
} else {
|
||||
$message = "Service $ServiceName status is abnormal: $($service.Status)"
|
||||
Write-Log $message -Level "ERROR"
|
||||
|
||||
Send-EmailNotification -Subject "服务异常:$ServiceName" -Body $message
|
||||
Send-SystemNotification -Title "服务异常" -Message $message
|
||||
|
||||
if ($AutoRestart) {
|
||||
Write-Log "Attempting to restart service: $ServiceName"
|
||||
try {
|
||||
Start-Service -Name $ServiceName -ErrorAction Stop
|
||||
Start-Sleep -Seconds 5
|
||||
|
||||
$serviceAfterRestart = Get-Service -Name $ServiceName -ErrorAction Stop
|
||||
if ($serviceAfterRestart.Status -eq "Running") {
|
||||
$successMessage = "Service $ServiceName restarted successfully"
|
||||
Write-Log $successMessage
|
||||
Send-EmailNotification -Subject "服务已重启:$ServiceName" -Body $successMessage
|
||||
Send-SystemNotification -Title "服务已重启" -Message $successMessage
|
||||
return $true
|
||||
} else {
|
||||
$failMessage = "Service $ServiceName restart failed, current status: $($serviceAfterRestart.Status)"
|
||||
Write-Log $failMessage -Level "ERROR"
|
||||
Send-EmailNotification -Subject "服务重启失败:$ServiceName" -Body $failMessage
|
||||
Send-SystemNotification -Title "服务重启失败" -Message $failMessage
|
||||
return $false
|
||||
}
|
||||
} catch {
|
||||
$errorMessage = "Failed to restart service $ServiceName: $_"
|
||||
Write-Log $errorMessage -Level "ERROR"
|
||||
Send-EmailNotification -Subject "服务重启失败:$ServiceName" -Body $errorMessage
|
||||
Send-SystemNotification -Title "服务重启失败" -Message $errorMessage
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
} catch {
|
||||
$errorMessage = "Service $ServiceName not found or access denied: $_"
|
||||
Write-Log $errorMessage -Level "ERROR"
|
||||
Send-EmailNotification -Subject "服务不存在:$ServiceName" -Body $errorMessage
|
||||
Send-SystemNotification -Title "服务不存在" -Message $errorMessage
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Check-ServiceHealth {
|
||||
Write-Log "Starting service health check for: $ServiceName"
|
||||
|
||||
try {
|
||||
$service = Get-Service -Name $ServiceName -ErrorAction Stop
|
||||
|
||||
if ($service.Status -ne "Running") {
|
||||
Write-Log "Service is not running, skipping health check" -Level "WARN"
|
||||
return $false
|
||||
}
|
||||
|
||||
$logPath = Join-Path $LogDir "nssm_stderr.log"
|
||||
if (Test-Path $logPath) {
|
||||
$lastErrorTime = (Get-Item $logPath).LastWriteTime
|
||||
$timeSinceLastError = (Get-Date) - $lastErrorTime
|
||||
|
||||
if ($timeSinceLastError.TotalMinutes -lt 5) {
|
||||
$errorCount = (Get-Content $logPath -Tail 100 | Select-String -Pattern "ERROR|Exception|Failed" | Measure-Object).Count
|
||||
if ($errorCount -gt 0) {
|
||||
$message = "Service $ServiceName has recent errors in log file: $errorCount errors in last 5 minutes"
|
||||
Write-Log $message -Level "WARN"
|
||||
Send-EmailNotification -Subject "服务日志异常:$ServiceName" -Body $message
|
||||
Send-SystemNotification -Title "服务日志异常" -Message $message
|
||||
return $false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Log "Service health check passed for: $ServiceName"
|
||||
return $true
|
||||
} catch {
|
||||
Write-Log "Health check failed for service $ServiceName: $_" -Level "ERROR"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Main {
|
||||
Write-Log "========================================"
|
||||
Write-Log "Service Daemon Started"
|
||||
Write-Log "Service Name: $ServiceName"
|
||||
Write-Log "Email Enabled: $EmailEnabled"
|
||||
Write-Log "System Notification: $SystemNotification"
|
||||
Write-Log "Auto Restart: $AutoRestart"
|
||||
Write-Log "========================================"
|
||||
|
||||
$statusCheck = Check-ServiceStatus
|
||||
|
||||
if ($statusCheck) {
|
||||
$healthCheck = Check-ServiceHealth
|
||||
if (-not $healthCheck) {
|
||||
Write-Log "Service health check failed" -Level "WARN"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Log "Service Daemon Completed"
|
||||
Write-Log "========================================"
|
||||
}
|
||||
|
||||
try {
|
||||
Main
|
||||
} catch {
|
||||
Write-Log "Fatal error in service daemon: $_" -Level "ERROR"
|
||||
Send-EmailNotification -Subject "守护脚本错误" -Body "Service daemon script encountered a fatal error: $_"
|
||||
Send-SystemNotification -Title "守护脚本错误" -Message "Service daemon script encountered a fatal error"
|
||||
exit 1
|
||||
}
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,205 @@
|
||||
# 服务守护脚本使用指南
|
||||
|
||||
## 概述
|
||||
服务守护脚本为 MyAPS_API 服务提供自动化监控和通知功能。
|
||||
|
||||
## 创建的文件
|
||||
- `service_daemon.ps1` - 主守护脚本
|
||||
|
||||
## 配置
|
||||
|
||||
### 方法 1:.env 文件(推荐)
|
||||
脚本会自动从位于 `d:\myaps_api\myaps_api\.env` 的 `.env` 文件读取配置。
|
||||
|
||||
编辑 `.env` 文件来配置服务守护:
|
||||
|
||||
```env
|
||||
# 服务守护配置
|
||||
# 服务名称
|
||||
SERVICE_DAEMON_NAME=MyAPS_API
|
||||
# 日志目录
|
||||
SERVICE_DAEMON_LOG_DIR=d:\myaps_api\myaps_api\logs
|
||||
# 启用邮件通知
|
||||
SERVICE_DAEMON_EMAIL_ENABLED=false
|
||||
# 邮件接收地址
|
||||
SERVICE_DAEMON_EMAIL_TO=
|
||||
# 邮件发送地址
|
||||
SERVICE_DAEMON_EMAIL_FROM=
|
||||
# SMTP服务器
|
||||
SERVICE_DAEMON_SMTP_SERVER=
|
||||
# SMTP端口
|
||||
SERVICE_DAEMON_SMTP_PORT=587
|
||||
# SMTP用户名
|
||||
SERVICE_DAEMON_SMTP_USER=
|
||||
# SMTP密码
|
||||
SERVICE_DAEMON_SMTP_PASSWORD=
|
||||
# 启用系统通知
|
||||
SERVICE_DAEMON_SYSTEM_NOTIFICATION=true
|
||||
# 启用自动重启
|
||||
SERVICE_DAEMON_AUTO_RESTART=true
|
||||
```
|
||||
|
||||
### 方法 2:命令行参数
|
||||
使用参数运行脚本:
|
||||
```powershell
|
||||
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "d:\myaps_api\myaps_api\scripts\service_daemon.ps1" -ServiceName "MyAPS_API" -EmailEnabled "true" -EmailTo "admin@example.com" -EmailFrom "monitor@example.com" -SmtpServer "smtp.example.com" -SmtpPort 587 -SmtpUser "your_email@example.com" -SmtpPassword "your_password" -SystemNotification $true -AutoRestart $true
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 参数
|
||||
|
||||
| 参数 | 类型 | 默认值 | 描述 |
|
||||
|------|------|--------|------|
|
||||
| ServiceName | 字符串 | MyAPS_API | 要监控的服务名称 |
|
||||
| LogDir | 字符串 | d:\myaps_api\myaps_api\logs | 日志文件目录 |
|
||||
| EmailEnabled | 字符串 | false | 启用邮件通知(true/false) |
|
||||
| EmailTo | 字符串 | "" | 收件人电子邮件地址 |
|
||||
| EmailFrom | 字符串 | "" | 发件人电子邮件地址 |
|
||||
| SmtpServer | 字符串 | "" | SMTP 服务器地址 |
|
||||
| SmtpPort | 整数 | 587 | SMTP 服务器端口 |
|
||||
| SmtpUser | 字符串 | "" | SMTP 用户名 |
|
||||
| SmtpPassword | 字符串 | "" | SMTP 密码 |
|
||||
| SystemNotification | 布尔值 | true | 启用 Windows 系统通知 |
|
||||
| AutoRestart | 布尔值 | true | 自动重启失败的服务 |
|
||||
| EnvFile | 字符串 | 自动计算 | 环境配置文件路径 |
|
||||
|
||||
## 设置计划任务
|
||||
|
||||
### 使用任务计划程序 GUI:
|
||||
1. 打开任务计划程序(taskschd.msc)
|
||||
2. 右键单击 "任务计划程序库" > "创建任务"
|
||||
3. 常规选项卡:
|
||||
- 名称:"MyAPS_API 服务守护"
|
||||
- 安全选项:"不管用户是否登录都要运行"
|
||||
- 勾选 "使用最高权限运行"
|
||||
4. 触发器选项卡:
|
||||
- 点击 "新建"
|
||||
- 开始任务:"按计划"
|
||||
- 设置:"每天" 或 "重复任务间隔:5分钟"
|
||||
- 点击确定
|
||||
5. 操作选项卡:
|
||||
- 点击 "新建"
|
||||
- 操作:"启动程序"
|
||||
- 程序/脚本:`powershell.exe`
|
||||
- 添加参数:`-ExecutionPolicy Bypass -NoProfile -File "d:\myaps_api\myaps_api\scripts\service_daemon.ps1" `
|
||||
- 点击确定
|
||||
6. 条件选项卡:
|
||||
- 取消勾选 "只有在计算机使用交流电源时才启动任务"(如适用)
|
||||
7. 设置选项卡:
|
||||
- 勾选 "允许按需运行任务"
|
||||
- 勾选 "如果错过计划开始时间,立即运行任务"
|
||||
8. 点击确定创建任务
|
||||
|
||||
### 使用 PowerShell 命令:
|
||||
```powershell
|
||||
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -NoProfile -File 'd:\myaps_api\myaps_api\scripts\service_daemon.ps1' -ServiceName 'MyAPS_API' -SystemNotification `$true -AutoRestart `$true"
|
||||
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 5)
|
||||
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
||||
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -DontStopOnIdleEnd
|
||||
|
||||
Register-ScheduledTask -TaskName "MyAPS_API Service Daemon" -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force
|
||||
```
|
||||
|
||||
## 监控功能
|
||||
|
||||
### 1. 服务状态检查
|
||||
- 监控服务是否运行
|
||||
- 检查服务是否存在
|
||||
- 检测服务状态变化
|
||||
|
||||
### 2. 自动重启
|
||||
- 尝试重启失败的服务
|
||||
- 等待 5 秒后检查重启状态
|
||||
- 记录重启尝试和结果
|
||||
|
||||
### 3. 邮件通知
|
||||
- 服务停止时发送警报
|
||||
- 服务成功重启时通知
|
||||
- 报告重启失败
|
||||
- 服务未找到时发送警报
|
||||
|
||||
### 4. 系统通知
|
||||
- 显示 Windows 系统托盘通知
|
||||
- 显示服务状态变化
|
||||
- 提供视觉警报以便立即关注
|
||||
|
||||
### 5. 健康检查
|
||||
- 监控错误日志文件
|
||||
- 检查最近的错误(最后 5 分钟)
|
||||
- 如果检测到日志中的错误则发出警报
|
||||
|
||||
## 日志文件
|
||||
|
||||
### service_daemon.log
|
||||
- 包含所有守护活动
|
||||
- 包括时间戳和状态信息
|
||||
- 跟踪成功的操作
|
||||
|
||||
### service_daemon_errors.log
|
||||
- 仅包含错误消息
|
||||
- 用于故障排除
|
||||
- 帮助识别重复出现的问题
|
||||
|
||||
## 测试守护脚本
|
||||
|
||||
### 手动测试:
|
||||
```powershell
|
||||
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "d:\myaps_api\myaps_api\scripts\service_daemon.ps1" -ServiceName "MyAPS_API" -SystemNotification $true -AutoRestart $false
|
||||
```
|
||||
|
||||
### 测试场景:
|
||||
1. 手动停止服务并运行守护脚本
|
||||
2. 验证收到邮件通知
|
||||
3. 检查系统通知是否出现
|
||||
4. 测试自动重启功能
|
||||
5. 查看日志文件以确保正确记录
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 脚本未运行:
|
||||
- 检查 PowerShell 执行策略
|
||||
- 验证文件路径是否正确
|
||||
- 确保具有适当的权限
|
||||
|
||||
### 邮件未发送:
|
||||
- 验证 SMTP 服务器设置
|
||||
- 检查网络连接
|
||||
- 确认电子邮件凭据正确
|
||||
- 检查防火墙设置
|
||||
|
||||
### 系统通知未出现:
|
||||
- 确保 Windows 通知已启用
|
||||
- 检查脚本是否以适当的权限运行
|
||||
- 验证 Windows 中的通知设置
|
||||
|
||||
### 服务未重启:
|
||||
- 检查服务是否具有适当的权限
|
||||
- 验证服务依赖项是否正在运行
|
||||
- 查看服务事件日志
|
||||
|
||||
## 安全考虑
|
||||
|
||||
1. **电子邮件凭据**:安全存储 SMTP 密码
|
||||
2. **文件权限**:限制对配置文件的访问
|
||||
3. **服务账户**:使用适当的服务账户权限
|
||||
4. **日志文件**:定期查看和清理日志文件
|
||||
|
||||
## 维护
|
||||
|
||||
### 定期任务:
|
||||
- 每周查看日志文件
|
||||
- 根据需要更新电子邮件配置
|
||||
- 每月测试守护脚本功能
|
||||
- 清理旧日志文件
|
||||
|
||||
### 日志轮转:
|
||||
考虑设置日志轮转以防止日志文件变得过大。您可以使用 log_rotate.ps1 脚本进行此操作。
|
||||
|
||||
## 支持
|
||||
|
||||
对于问题或疑问:
|
||||
1. 检查日志文件中的错误消息
|
||||
2. 验证所有配置参数
|
||||
3. 在调度前手动测试脚本
|
||||
4. 查看 Windows 事件日志以了解服务问题
|
||||
@@ -5,11 +5,21 @@ setlocal
|
||||
|
||||
set "SCRIPT_DIR=%~dp0"
|
||||
set "NSSM_EXE=%SCRIPT_DIR%nssm.exe"
|
||||
set "SERVICE_NAME=MyAPS_API"
|
||||
set "RUN_PS1=%SCRIPT_DIR%run.ps1"
|
||||
|
||||
rem Calculate project root (parent directory of scripts)
|
||||
for %%i in ("%SCRIPT_DIR%..") do set "PROJECT_ROOT=%%~fi"
|
||||
|
||||
rem Read service name from .env file
|
||||
if exist "%PROJECT_ROOT%\.env" (
|
||||
for /f "tokens=1,2 delims==" %%a in ('findstr "^SERVICE_DAEMON_NAME=" "%PROJECT_ROOT%\.env"') do (
|
||||
set "SERVICE_NAME=%%b"
|
||||
)
|
||||
)
|
||||
|
||||
rem Set default service name if not found in .env
|
||||
if "%SERVICE_NAME%"=="" set "SERVICE_NAME=MyAPS_API"
|
||||
|
||||
set "LOG_DIR=%PROJECT_ROOT%\logs"
|
||||
|
||||
rem Check if NSSM exists
|
||||
@@ -47,6 +57,7 @@ echo 5. Uninstall service
|
||||
echo 6. Check status
|
||||
echo 7. Test run.ps1 (dev mode)
|
||||
echo 8. Test run.ps1 (service mode)
|
||||
echo 9. Clean old logs (keep 10 days)
|
||||
echo 0. Exit
|
||||
|
||||
echo.
|
||||
@@ -60,6 +71,7 @@ if "%choice%"=="5" goto :UNINSTALL
|
||||
if "%choice%"=="6" goto :STATUS
|
||||
if "%choice%"=="7" goto :TEST_RUNPS1_DEV
|
||||
if "%choice%"=="8" goto :TEST_RUNPS1_SERVICE
|
||||
if "%choice%"=="9" goto :CLEAN_LOGS
|
||||
if "%choice%"=="0" goto :EXIT
|
||||
|
||||
echo Invalid choice
|
||||
@@ -85,6 +97,14 @@ goto :MENU
|
||||
"%NSSM_EXE%" set "%SERVICE_NAME%" AppStdout "%LOG_DIR%\nssm_stdout.log"
|
||||
"%NSSM_EXE%" set "%SERVICE_NAME%" AppStderr "%LOG_DIR%\nssm_stderr.log"
|
||||
|
||||
rem Configure automatic restart on failure
|
||||
echo Configuring automatic restart settings...
|
||||
"%NSSM_EXE%" set "%SERVICE_NAME%" AppRestartDelay 60000
|
||||
"%NSSM_EXE%" set "%SERVICE_NAME%" AppThrottle 300000
|
||||
"%NSSM_EXE%" set "%SERVICE_NAME%" AppExit Default Restart
|
||||
"%NSSM_EXE%" set "%SERVICE_NAME%" AppExit 1 Restart
|
||||
"%NSSM_EXE%" set "%SERVICE_NAME%" AppExit 0 Restart
|
||||
|
||||
echo Service installed
|
||||
echo Logs will be saved to: %LOG_DIR%
|
||||
pause
|
||||
@@ -165,6 +185,44 @@ goto :MENU
|
||||
pause
|
||||
goto :MENU
|
||||
|
||||
:CLEAN_LOGS
|
||||
echo Cleaning old logs...
|
||||
echo Log directory: %LOG_DIR%
|
||||
echo Keeping logs from the last 10 days...
|
||||
echo.
|
||||
|
||||
rem Use PowerShell to clean logs older than 10 days
|
||||
powershell.exe -ExecutionPolicy Bypass -NoProfile -Command "& {
|
||||
$logDir = '%LOG_DIR%';
|
||||
$daysToKeep = 10;
|
||||
$cutoffDate = (Get-Date).AddDays(-$daysToKeep);
|
||||
|
||||
if (Test-Path $logDir) {
|
||||
$oldLogs = Get-ChildItem -Path $logDir -Recurse -File | Where-Object { $_.LastWriteTime -lt $cutoffDate };
|
||||
|
||||
if ($oldLogs.Count -gt 0) {
|
||||
Write-Host "Found $($oldLogs.Count) old log files to delete:";
|
||||
$oldLogs | ForEach-Object { Write-Host "- $($_.Name) (Last modified: $($_.LastWriteTime))" };
|
||||
|
||||
try {
|
||||
$oldLogs | Remove-Item -Force;
|
||||
Write-Host "Successfully deleted $($oldLogs.Count) old log files.";
|
||||
} catch {
|
||||
Write-Host "Error deleting log files: $_" -ForegroundColor Red;
|
||||
}
|
||||
} else {
|
||||
Write-Host "No old log files found. All logs are within the last $daysToKeep days.";
|
||||
}
|
||||
} else {
|
||||
Write-Host "Log directory does not exist: $logDir" -ForegroundColor Yellow;
|
||||
}
|
||||
}"
|
||||
|
||||
echo.
|
||||
echo Log cleaning completed.
|
||||
pause
|
||||
goto :MENU
|
||||
|
||||
:EXIT
|
||||
echo Exiting...
|
||||
pause
|
||||
|
||||
Reference in New Issue
Block a user