Download src/agent_process_dashboard/actions.py from smlflg/agent-process-dashboard: direct link, hf CLI and curl.
- Browser
- Download file 4.49 kB
-
https://huggingface.co/smlflg/agent-process-dashboard/resolve/main/src/agent_process_dashboard/actions.py
- Command line
-
hf download hf://smlflg/agent-process-dashboard/src/agent_process_dashboard/actions.py
-
curl -L -o actions.py https://huggingface.co/smlflg/agent-process-dashboard/resolve/main/src/agent_process_dashboard/actions.py
4.49 kB
| from __future__ import annotations | |
| from collections.abc import Callable | |
| from dataclasses import dataclass | |
| import os | |
| import signal | |
| from .models import DashboardSnapshot | |
| from .procfs import sample_process | |
| from .snapshot import build_snapshot | |
| SignalName = str | |
| SnapshotBuilder = Callable[[], DashboardSnapshot] | |
| SignalSender = Callable[[int, int], None] | |
| SUPPORTED_SIGNALS: dict[SignalName, int] = { | |
| "TERM": signal.SIGTERM, | |
| "KILL": signal.SIGKILL, | |
| } | |
| class ProcessActionRequest: | |
| pid: int | |
| process_key: str | |
| signal_name: SignalName = "TERM" | |
| class ProcessActionResult: | |
| ok: bool | |
| status: str | |
| message: str | |
| pid: int | |
| process_key: str | |
| signal_name: SignalName | |
| def send_signal_to_candidate( | |
| request: ProcessActionRequest, | |
| *, | |
| snapshot_builder: SnapshotBuilder | None = None, | |
| signal_sender: SignalSender = os.kill, | |
| current_pid: int | None = None, | |
| ) -> ProcessActionResult: | |
| """Send a signal only if the PID still matches a current dry-run candidate.""" | |
| current_pid = os.getpid() if current_pid is None else current_pid | |
| snapshot_builder = snapshot_builder or build_snapshot | |
| signal_number = SUPPORTED_SIGNALS.get(request.signal_name) | |
| if signal_number is None: | |
| return _result( | |
| request, | |
| ok=False, | |
| status="invalid_signal", | |
| message=f"Signal {request.signal_name} wird nicht unterstützt.", | |
| ) | |
| if request.pid == current_pid: | |
| return _result( | |
| request, | |
| ok=False, | |
| status="self_process", | |
| message="Der Dashboard-Prozess selbst wird nicht beendet.", | |
| ) | |
| snapshot = snapshot_builder() | |
| live = next((sample for sample in snapshot.processes if sample.pid == request.pid), None) | |
| if live is None: | |
| return _result( | |
| request, | |
| ok=False, | |
| status="not_found", | |
| message=( | |
| f"PID {request.pid} läuft nicht mehr oder ist für den aktuellen User " | |
| "nicht sichtbar." | |
| ), | |
| ) | |
| if live.process_key != request.process_key: | |
| return _result( | |
| request, | |
| ok=False, | |
| status="pid_reused", | |
| message=( | |
| f"PID {request.pid} gehört inzwischen zu einem anderen Prozess. " | |
| "Es wurde kein Signal gesendet." | |
| ), | |
| ) | |
| candidate = next( | |
| ( | |
| item | |
| for item in snapshot.dry_run.candidates | |
| if item.pid == request.pid and item.process_key == request.process_key | |
| ), | |
| None, | |
| ) | |
| if candidate is None: | |
| return _result( | |
| request, | |
| ok=False, | |
| status="not_candidate", | |
| message=( | |
| f"PID {request.pid} ist kein aktueller Dry-run-Kandidat. " | |
| "Es wurde kein Signal gesendet." | |
| ), | |
| ) | |
| try: | |
| signal_sender(request.pid, signal_number) | |
| except ProcessLookupError: | |
| return _result( | |
| request, | |
| ok=False, | |
| status="not_found", | |
| message=f"PID {request.pid} ist vor dem Signal verschwunden.", | |
| ) | |
| except PermissionError: | |
| return _result( | |
| request, | |
| ok=False, | |
| status="permission_denied", | |
| message=f"Keine Berechtigung, Signal {request.signal_name} an PID {request.pid} zu senden.", | |
| ) | |
| except OSError as exc: | |
| return _result( | |
| request, | |
| ok=False, | |
| status="signal_failed", | |
| message=f"Signal {request.signal_name} an PID {request.pid} ist fehlgeschlagen: {exc}", | |
| ) | |
| return _result( | |
| request, | |
| ok=True, | |
| status="sent", | |
| message=f"Signal {request.signal_name} wurde an PID {request.pid} gesendet.", | |
| ) | |
| def same_process_is_running( | |
| pid: int, | |
| process_key: str, | |
| *, | |
| proc_root: str = "/proc", | |
| ) -> bool: | |
| sample = sample_process(pid, proc_root=proc_root, current_uid_only=True) | |
| return sample is not None and sample.process_key == process_key | |
| def _result( | |
| request: ProcessActionRequest, | |
| *, | |
| ok: bool, | |
| status: str, | |
| message: str, | |
| ) -> ProcessActionResult: | |
| return ProcessActionResult( | |
| ok=ok, | |
| status=status, | |
| message=message, | |
| pid=request.pid, | |
| process_key=request.process_key, | |
| signal_name=request.signal_name, | |
| ) | |