From af4e90357f83b8cd36359020f4d7d879542ec696 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Wed, 13 Aug 2025 11:08:38 -0700 Subject: [PATCH] More debug on watching --- cista/watching.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/cista/watching.py b/cista/watching.py index 6e03872..95a57df 100644 --- a/cista/watching.py +++ b/cista/watching.py @@ -1,4 +1,5 @@ import asyncio +import os import shutil import sys import threading @@ -7,6 +8,7 @@ from contextlib import suppress from os import stat_result from pathlib import Path, PurePosixPath from stat import S_ISDIR, S_ISREG +import signal import msgspec from natsort import humansorted, natsort_keygen, ns @@ -174,6 +176,9 @@ state = State() rootpath: Path = None # type: ignore quit = threading.Event() +# Keep a reference so the file stays open for faulthandler outputs +_faulthandler_file = None # type: ignore + ## Filesystem scanning @@ -574,6 +579,29 @@ async def start(app, loop): global rootpath config.load_config() rootpath = config.config.path + # Optional: enable SIGUSR1 stack dumps in production for debugging hangs + # Control with env CISTA_STACK_DUMP (default: enabled). Sends all thread + # stacks to a per-process log in /tmp when receiving SIGUSR1. + if os.environ.get("CISTA_STACK_DUMP", "1") == "1": + try: + import faulthandler + + global _faulthandler_file + if _faulthandler_file is None: + log_path = f"/tmp/cista-stacks-{os.getpid()}.log" + # Line-buffered text file so writes appear promptly + _faulthandler_file = open(log_path, "a", buffering=1) + faulthandler.enable(file=_faulthandler_file) + faulthandler.register( + signal.SIGUSR1, file=_faulthandler_file, all_threads=True, chain=True + ) + logger.info( + "Stack dump enabled: send SIGUSR1 to PID %s to write all thread stacks to %s", + os.getpid(), + log_path, + ) + except Exception: + logger.exception("Failed to enable SIGUSR1 stack dump handler") use_inotify = sys.platform == "linux" app.ctx.watcher = threading.Thread( target=watcher_inotify if use_inotify else watcher_poll,