# <<*>> -^v- SNOWARE APPLICATION # usage: Notify systemd. # author: S.A. # time: 2026-06-07 # Copyright (c) [2026] [S.A. SNOWARE-SCU] # [MineSentinel] is licensed under Mulan PubL v2. # You can use this software according to the terms and conditions of the Mulan PubL v2. # You may obtain a copy of Mulan PubL v2 at: # http://license.coscl.org.cn/MulanPubL-2.0 # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. # See the Mulan PubL v2 for more details. # frozen_string_literal: true # Sends keep-alive notifications (including WATCHDOG=1) to systemd # via the NOTIFY_SOCKET datagram socket, enabling service supervision. class SystemdNotifier require_relative 'method_executor' @notify_socket = ENV.fetch('NOTIFY_SOCKET', nil) @watchdog_usec = (ENV['WATCHDOG_USEC'] || '0').to_i if @notify_socket && File.socket?(@notify_socket) MethodExecutor.record('debug', 'heartbeat', 'Found NOTIFY_SOCKET, enabling heartbeat') @enable_heartbeat = true # Fix(2026-06-08): 将 UNIXSocket(SOCK_STREAM) 改为 SOCK_DGRAM # systemd NOTIFY_SOCKET 是 datagram socket,用 stream socket 连接会报 # Protocol wrong type for socket (Errno::EPROTOTYPE) @socket = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM) @socket.connect(Socket.pack_sockaddr_un(@notify_socket)) MethodExecutor.record('debug', 'heartbeat', 'Heartbeat socket opened') else MethodExecutor.record('error', 'heartbeat', 'NOTIFY_SOCKET is not set or is not a socket, am I a service?') @enable_heartbeat = false end # @return [Boolean] def enabled? @enable_heartbeat end # @param message [String] # @return [void] def self.notify(message) return unless @enable_heartbeat begin @socket.send(message, 0) MethodExecutor.record('debug', 'heartbeat', "Heartbeat sent: #{message}") rescue StandardError => e MethodExecutor.record('error', 'heartbeat', "Failed to send heartbeat: #{e}") @enable_heartbeat = false end end end