macOS下程序化检测程序崩溃:Snafu多实例场景解决方案问询
Great question—dealing with black-box multi-instance crash detection can be tricky, especially when you can't rely on PID tracking or the app itself reporting its state. Let's break this down into your two main requirements with practical, actionable solutions:
ps | grep) Since you're running Snafu unattended and need per-instance tracking, these methods avoid parsing process lists and work with black-box constraints:
Use a Wrapper Process with Exit Monitoring (Most Reliable)
Create a lightweight wrapper script/process for each Snafu instance. When the wrapper launches Snafu as a child, it can directly monitor the child's exit status—no PID required. Whether Snafu crashes, exits normally, or gets killed, the wrapper will be notified instantly.- For crashes, the exit status will reflect a signal-induced termination (e.g.,
SIGSEGVfor segmentation faults). - Each wrapper maps to exactly one instance, so you can track crashes per instance without confusion.
- Example bash wrapper snippet:
#!/bin/bash # Generate a unique ID for tracking this instance INSTANCE_ID=$(uuidgen) echo "Starting Snafu instance $INSTANCE_ID at $(date)" # Launch Snafu and wait for it to exit ./Snafu EXIT_STATUS=$? # Check if exit was due to a crash (signal) if [ $((EXIT_STATUS & 127)) -ne 0 ]; then SIGNAL=$((EXIT_STATUS & 127)) echo "ALERT: Snafu instance $INSTANCE_ID crashed with signal $SIGNAL at $(date)" # Add your recovery logic here (restart, send alert, etc.) fi
- For crashes, the exit status will reflect a signal-induced termination (e.g.,
Per-Instance Heartbeat Mechanism
If you can pass arguments to Snafu (or inject a small wrapper alongside it), assign each instance a unique heartbeat channel:- Generate a UUID for each instance at startup, and have Snafu periodically update a timestamp in a dedicated temp file (e.g.,
/tmp/snafu-heartbeats/$INSTANCE_ID) or send a local UDP packet to a port tied to its ID. - Your monitoring process checks each heartbeat at set intervals. If a timestamp isn't updated within a threshold, mark that instance as crashed.
- Note: This only works if Snafu can accept configuration to send heartbeats; if it's a strict black box with no inputs, skip this.
- Generate a UUID for each instance at startup, and have Snafu periodically update a timestamp in a dedicated temp file (e.g.,
Exclusive Resource Locking
Assign a unique auto-releasing resource to each instance. When the instance crashes, the OS will automatically release the resource, letting your monitor detect the failure:- For each instance, create a unique temp file and open it with an exclusive lock (using
flock -nin bash, or theO_EXCLflag in C). The instance holds this lock for its entire runtime. - Your monitor periodically tries to acquire the lock for each instance's file. If it succeeds, the original instance has crashed (since locks are released when processes terminate abruptly).
- For each instance, create a unique temp file and open it with an exclusive lock (using
macOS has system-specific tools and APIs tailored for crash monitoring—here are the most practical options:
Monitor Diagnostic Report Directories
macOS automatically generates crash reports for crashed processes, stored in:- User-specific:
~/Library/Logs/DiagnosticReports/ - System-wide:
/Library/Logs/DiagnosticReports/
Reports are named likeSnafu_2024-05-20_14-30-00_MyMacBook.crash. To detect crashes programmatically: - Use file system monitoring (e.g.,
kqueuein C, thewatchdoglibrary in Python) to watch these directories for new files matching the Snafu pattern. - Parse the report to extract details like the
ProcessUUID(unique per process launch) and crash signal. If you track the UUID when launching each instance (viaps -o uuid= <pid>), you can map the crash report to a specific instance.
- User-specific:
Use
kqueueto Track Process Exit Events
macOS'skqueueAPI lets you monitor real-time process state changes. For a wrapper launching Snafu:- Create a kqueue and add an
EVFILT_PROCfilter for the child process, with theNOTE_EXITflag. - When the child crashes or exits, your wrapper will receive an event with exit status and signal details.
- Simplified C snippet example:
#include <sys/event.h> #include <sys/wait.h> #include <stdio.h> #include <unistd.h> int main() { pid_t child_pid = fork(); if (child_pid == 0) { // Child process: launch Snafu execl("./Snafu", "Snafu", NULL); _exit(1); } // Parent process: monitor child with kqueue int kq = kqueue(); struct kevent event; EV_SET(&event, child_pid, EVFILT_PROC, EV_ADD | EV_ENABLE, NOTE_EXIT, 0, NULL); kevent(kq, &event, 1, NULL, 0, NULL); struct kevent ev; int n = kevent(kq, NULL, 0, &ev, 1, NULL); if (n > 0 && ev.filter == EVFILT_PROC && ev.fflags & NOTE_EXIT) { int exit_signal = ev.data >> 8; printf("Snafu instance crashed with signal %d\n", exit_signal); } close(kq); return 0; }
For Python, use libraries like
pykqueueto interact with kqueue without writing C code.- Create a kqueue and add an
Leverage
launchdfor Managed Instances
If running Snafu as a service, macOS'slaunchdcan handle monitoring:- Create a unique
.plistfile for each instance (in~/Library/LaunchAgents/for user-level,/Library/LaunchDaemons/for system-level) with a distinctLabelattribute. - Set
KeepAlive = falseif you don't want automatic restarts, and configureStandardErrorPath/StandardOutPathto log output. - To detect crashes programmatically, query
launchctl listto check the process state, or monitor the log files for crash-related messages.
- Create a unique
AppleScript for GUI Snafu Instances
If Snafu is a GUI app, use AppleScript to check for running instances and detect crashes:- Run a script via
osascriptto verify if the instance is active:tell application "System Events" set instanceRunning to exists process "Snafu" whose name contains "unique-instance-tag" if not instanceRunning then return "CRASHED" end if end tell
For multi-instance GUI apps, identify instances by unique window titles or other UI attributes.
- Run a script via
内容的提问来源于stack exchange,提问作者duuuuxq

