Fork to background using the double-fork pattern. Redirects stdout/stderr to the daemon log file. Writes PID file. Sets up SIGTERM handler for graceful shutdown. On Windows, forking is not supported — the daemon runs in the foreground and a warning is logged.
(self)
| 804 | # ------------------------------------------------------------------ |
| 805 | |
| 806 | def daemonize(self) -> None: |
| 807 | """Fork to background using the double-fork pattern. |
| 808 | |
| 809 | Redirects stdout/stderr to the daemon log file. Writes PID file. |
| 810 | Sets up SIGTERM handler for graceful shutdown. |
| 811 | |
| 812 | On Windows, forking is not supported — the daemon runs in the |
| 813 | foreground and a warning is logged. |
| 814 | """ |
| 815 | if sys.platform == "win32": |
| 816 | logger.warning("Forking is not supported on Windows — running in foreground") |
| 817 | write_pid() |
| 818 | self._setup_signal_handlers() |
| 819 | return |
| 820 | |
| 821 | # First fork |
| 822 | pid = os.fork() |
| 823 | if pid > 0: |
| 824 | # Parent exits |
| 825 | sys.exit(0) |
| 826 | |
| 827 | # Become session leader |
| 828 | os.setsid() |
| 829 | |
| 830 | # Second fork (prevent acquiring a controlling terminal) |
| 831 | pid = os.fork() |
| 832 | if pid > 0: |
| 833 | sys.exit(0) |
| 834 | |
| 835 | # Redirect file descriptors |
| 836 | sys.stdout.flush() |
| 837 | sys.stderr.flush() |
| 838 | |
| 839 | self._config.log_dir.mkdir(parents=True, exist_ok=True) |
| 840 | log_file = self._config.log_dir / "daemon.log" |
| 841 | |
| 842 | # Open log file for stdout/stderr |
| 843 | fd = os.open( |
| 844 | str(log_file), |
| 845 | os.O_WRONLY | os.O_CREAT | os.O_APPEND, |
| 846 | 0o644, |
| 847 | ) |
| 848 | os.dup2(fd, sys.stdout.fileno()) |
| 849 | os.dup2(fd, sys.stderr.fileno()) |
| 850 | |
| 851 | # Redirect stdin from /dev/null |
| 852 | devnull = os.open(os.devnull, os.O_RDONLY) |
| 853 | os.dup2(devnull, sys.stdin.fileno()) |
| 854 | os.close(devnull) |
| 855 | if fd > 2: |
| 856 | os.close(fd) |
| 857 | |
| 858 | # Write PID file |
| 859 | write_pid() |
| 860 | |
| 861 | # Set up signal handlers |
| 862 | self._setup_signal_handlers() |
| 863 |
no test coverage detected