Fenrir was not cleaning up after itself properly. Fixed several possible stale file bugs and hopefully this problem is now gone.

This commit is contained in:
Storm Dragon
2026-05-18 17:59:47 -04:00
parent 096919a2da
commit 19194e73fc
4 changed files with 72 additions and 19 deletions
+5 -2
View File
@@ -106,14 +106,17 @@ def run_fenrir():
fenrirApp.proceed() fenrirApp.proceed()
except Exception as e: except Exception as e:
print(f"Error starting Fenrir: {e}", file=sys.stderr) print(f"Error starting Fenrir: {e}", file=sys.stderr)
sys.exit(1)
except KeyboardInterrupt:
print("Interrupted", file=sys.stderr)
sys.exit(1)
finally:
if fenrirApp and hasattr(fenrirApp, 'cleanup_on_error'): if fenrirApp and hasattr(fenrirApp, 'cleanup_on_error'):
try: try:
fenrirApp.cleanup_on_error() fenrirApp.cleanup_on_error()
except Exception as cleanup_error: except Exception as cleanup_error:
print( print(
f"Error during cleanup: {cleanup_error}", file=sys.stderr) f"Error during cleanup: {cleanup_error}", file=sys.stderr)
sys.exit(1)
finally:
if fenrirApp: if fenrirApp:
del fenrirApp del fenrirApp
# Clean up PID file if it exists # Clean up PID file if it exists
+27 -15
View File
@@ -5,6 +5,7 @@
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributors.
import os import os
import socket
import signal import signal
import sys import sys
import time import time
@@ -40,6 +41,7 @@ class FenrirManager:
# Set signal handlers after successful initialization # Set signal handlers after successful initialization
signal.signal(signal.SIGINT, self.capture_signal) signal.signal(signal.SIGINT, self.capture_signal)
signal.signal(signal.SIGTERM, self.capture_signal) signal.signal(signal.SIGTERM, self.capture_signal)
signal.signal(signal.SIGHUP, self.capture_signal)
self.signal_handlers_set = True self.signal_handlers_set = True
self.is_initialized = True self.is_initialized = True
@@ -381,9 +383,15 @@ class FenrirManager:
time.sleep(0.6) time.sleep(0.6)
for currentManager in self.environment["general"]["managerList"]: for currentManager in self.environment["general"]["managerList"]:
if self.environment["runtime"][currentManager]: try:
self.environment["runtime"][currentManager].shutdown() if (
del self.environment["runtime"][currentManager] currentManager in self.environment["runtime"]
and self.environment["runtime"][currentManager]
):
self.environment["runtime"][currentManager].shutdown()
del self.environment["runtime"][currentManager]
except Exception:
pass # Ignore errors during individual manager shutdown
self.environment = None self.environment = None
@@ -394,6 +402,7 @@ class FenrirManager:
if self.signal_handlers_set: if self.signal_handlers_set:
signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGINT, signal.SIG_DFL)
signal.signal(signal.SIGTERM, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL)
signal.signal(signal.SIGHUP, signal.SIG_DFL)
self.signal_handlers_set = False self.signal_handlers_set = False
# Clean up any initialized managers # Clean up any initialized managers
@@ -454,7 +463,6 @@ class FenrirManager:
# Clean up socket files that might not be removed by the driver # Clean up socket files that might not be removed by the driver
try: try:
socket_file = None socket_file = None
screen_driver = None
if ( if (
"runtime" in self.environment "runtime" in self.environment
and "SettingsManager" in self.environment["runtime"] and "SettingsManager" in self.environment["runtime"]
@@ -465,19 +473,9 @@ class FenrirManager:
].get_setting("remote", "socket_file") ].get_setting("remote", "socket_file")
except Exception: except Exception:
pass # Use default socket file path pass # Use default socket file path
try:
screen_driver = self.environment["runtime"][
"SettingsManager"
].get_setting("screen", "driver")
except Exception:
pass
if not socket_file: if not socket_file:
if screen_driver == "vcsaDriver": # Always clean up PID-specific socket
socket_file = "/tmp/fenrirscreenreader-deamon.sock"
if os.path.exists(socket_file):
os.unlink(socket_file)
pid_socket_file = ( pid_socket_file = (
"/tmp/fenrirscreenreader-" "/tmp/fenrirscreenreader-"
+ str(os.getpid()) + str(os.getpid())
@@ -485,6 +483,20 @@ class FenrirManager:
) )
if os.path.exists(pid_socket_file): if os.path.exists(pid_socket_file):
os.unlink(pid_socket_file) os.unlink(pid_socket_file)
# Clean up main socket only if it is stale (not active)
main_socket_file = "/tmp/fenrirscreenreader-deamon.sock"
if os.path.exists(main_socket_file):
try:
test_sock = socket.socket(
socket.AF_UNIX, socket.SOCK_STREAM
)
test_sock.settimeout(0.2)
test_sock.connect(main_socket_file)
except OSError:
os.unlink(main_socket_file)
finally:
test_sock.close()
elif os.path.exists(socket_file): elif os.path.exists(socket_file):
os.unlink(socket_file) os.unlink(socket_file)
remoteInstanceRegistry.remove_instance() remoteInstanceRegistry.remove_instance()
@@ -28,6 +28,7 @@ def write_instance(instance_data):
registry_dir = get_registry_dir() registry_dir = get_registry_dir()
os.makedirs(registry_dir, mode=0o755, exist_ok=True) os.makedirs(registry_dir, mode=0o755, exist_ok=True)
os.chmod(registry_dir, 0o755) os.chmod(registry_dir, 0o755)
prune_stale_instances()
instance_data["updated_at"] = time.time() instance_data["updated_at"] = time.time()
instance_path = get_instance_file(instance_data.get("pid")) instance_path = get_instance_file(instance_data.get("pid"))
with open(instance_path, "w", encoding="utf-8") as instance_file: with open(instance_path, "w", encoding="utf-8") as instance_file:
@@ -53,6 +54,39 @@ def process_exists(pid):
return False return False
def prune_stale_instances():
registry_dir = get_registry_dir()
try:
instance_files = os.listdir(registry_dir)
except FileNotFoundError:
return
now = time.time()
for instance_name in instance_files:
instance_path = os.path.join(registry_dir, instance_name)
try:
with open(instance_path, "r", encoding="utf-8") as instance_file:
instance_data = json.load(instance_file)
pid = int(instance_data.get("pid", 0))
updated_at = float(instance_data.get("updated_at", 0))
except (OSError, ValueError, TypeError, json.JSONDecodeError):
try:
os.unlink(instance_path)
except OSError:
pass
continue
if (
not pid
or not process_exists(pid)
or now - updated_at > INSTANCE_TIMEOUT_SEC
):
try:
os.unlink(instance_path)
except OSError:
pass
def list_instances(): def list_instances():
registry_dir = get_registry_dir() registry_dir = get_registry_dir()
instances = [] instances = []
@@ -72,7 +106,11 @@ def list_instances():
except (OSError, ValueError, TypeError, json.JSONDecodeError): except (OSError, ValueError, TypeError, json.JSONDecodeError):
continue continue
if not pid or not process_exists(pid) or now - updated_at > INSTANCE_TIMEOUT_SEC: if (
not pid
or not process_exists(pid)
or now - updated_at > INSTANCE_TIMEOUT_SEC
):
try: try:
os.unlink(instance_path) os.unlink(instance_path)
except OSError: except OSError:
+1 -1
View File
@@ -4,5 +4,5 @@
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors. # By Chrys, Storm Dragon, and contributors.
version = "2026.05.14" version = "2026.05.18"
code_name = "testing" code_name = "testing"