使用PowerShell调用Cloudflare API清除文件时随机停止工作
Hey there! Let's troubleshoot why your file-monitoring + Cloudflare cache purge service keeps randomly dying. I’ve dealt with a ton of PS2EXE/NSSM service quirks before, so here’s a breakdown of the most likely culprits and fixes to try:
PowerShell scripts (especially when compiled to EXEs) will crash silently if they hit an unhandled exception—no console output to tell you why. Fix this by wrapping your entire logic in a global try/catch block and writing detailed error logs to a file:
# Set error handling to catch non-terminating errors too $ErrorActionPreference = "Stop" try { # Your entire file watcher setup + Cloudflare API logic goes here } catch { # Write timestamped error details (including stack trace) to a log file $errorLogPath = "C:\Services\CloudflarePurge\service-errors.log" $errorMsg = @" $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - FATAL ERROR: Exception Message: $_ Stack Trace: $($_.ScriptStackTrace) "@ Add-Content -Path $errorLogPath -Value $errorMsg -Encoding UTF8 # Optional: Exit with a non-zero code so NSSM knows to restart the service exit 1 }
This will give you concrete details about exactly what’s crashing the service.
The FileSystemWatcher class has built-in quirks that can crash your script if not addressed:
- Buffer Overflow: The default 8KB buffer gets overwhelmed if you have bulk file changes (e.g., batch uploads). Increase it to a larger value (max 64MB):
$watcher = New-Object System.IO.FileSystemWatcher $watcher.BufferSize = 65536 # 64KB - adjust based on your needs - Blocking Event Handlers: If your Cloudflare API call takes too long or hangs, it can lock up the watcher’s event thread. Offload API calls to a background job to avoid blocking:
Register-ObjectEvent $watcher "Changed" -Action { $targetFile = $eventArgs.FullPath # Spin up a background job to handle the API call without blocking the watcher Start-Job -ScriptBlock { param($file) # Your Cloudflare purge logic here (include error handling!) } -ArgumentList $targetFile | Out-Null } - Duplicate Events: The watcher often fires multiple events for a single file change. Add a debounce check to skip redundant calls (e.g., ignore events within 2 seconds of the last one for the same file):
$lastProcessed = @{} Register-ObjectEvent $watcher "Changed" -Action { $file = $eventArgs.FullPath $now = Get-Date if ($lastProcessed.ContainsKey($file) -and ($now - $lastProcessed[$file]).TotalSeconds -lt 2) { return # Skip duplicate event } $lastProcessed[$file] = $now # Proceed with API call }
Compiling PowerShell to EXE with PS2EXE introduces environment quirks:
- Permission Problems: NSSM defaults to running services under the Local System account, which may lack access to your monitored directory or internet permissions for Cloudflare API calls. Reconfigure the service to use a local user or domain account with explicit read access to the directory and internet access.
- Isolated Environment: Compiled EXEs run in a stripped-down session. Log environment variables at startup to check for missing dependencies (e.g., API keys stored in env vars):
$debugLogPath = "C:\Services\CloudflarePurge\service-debug.log" Add-Content -Path $debugLogPath -Value "$(Get-Date) - Environment Variables:`n$(Get-ChildItem Env: | Out-String)" -Encoding UTF8 - Window Style Conflicts: If you used
-WindowStyle Hiddenwhen compiling, try using-NoConsoleinstead—hidden windows can sometimes cause process hangs on certain Windows versions.
Make sure NSSM is set up to recover from crashes:
- Enable Auto-Restart: Open the NSSM service properties, go to the Recovery tab, and set First failure, Second failure, and Subsequent failures to Restart the service. Set a restart delay (e.g., 1 minute) to avoid thrashing.
- Check NSSM Logs: NSSM logs service startup/stop/crash details in its installation directory (default:
C:\Program Files\nssm\logs). Look for exit codes or error messages that indicate why the process terminated. - Avoid NSSM Output Redirection: Don’t use NSSM’s built-in console output redirection—write logs directly from your script instead, as large log files or permission issues can cause the service to stop.
Flaky API calls can crash your script if not handled:
- Add Timeouts: Prevent hanging API calls by setting a timeout in
Invoke-RestMethod/Invoke-WebRequest:Invoke-RestMethod -Uri "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/purge_cache" ` -Method POST ` -Headers $headers ` -Body $purgeBody ` -TimeoutSec 30 - Handle API Errors: Cloudflare returns detailed error objects even when requests fail. Catch these and log them instead of letting the script crash:
try { $response = Invoke-RestMethod -Uri $apiUri -Method POST -Headers $headers -Body $purgeBody -TimeoutSec 30 if (-not $response.success) { $errorMsg = "$(Get-Date) - Cloudflare API Failed: $($response.errors | ConvertTo-Json)" Add-Content -Path $errorLogPath -Value $errorMsg -Encoding UTF8 } } catch { $errorMsg = "$(Get-Date) - API Call Failed: $_`n$($_.ScriptStackTrace)" Add-Content -Path $errorLogPath -Value $errorMsg -Encoding UTF8 }
Start with adding the global error logging—it’ll tell you exactly what’s going wrong, making the rest of the troubleshooting straightforward.
内容的提问来源于stack exchange,提问作者227Passive




