daemon

package
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	CtrlStop = "stop"
	CtrlKill = "kill"
	CtrlPing = "ping"
)

controlCommand 是 Worker 通过 ChannelControl 下发的控制命令。 约定 payload 为 "stop" / "kill" / "ping" 文本。

View Source
const (
	ControlStop = CtrlStop
	ControlKill = CtrlKill
	ControlPing = CtrlPing
)

ControlStop / ControlKill / ControlPing 是导出的控制命令常量, 供 daemonStrategy 跨包引用。

View Source
const (
	EnvWrapperConfig = "JM_DAEMON_WRAPPER_CONFIG" // JSON 编码的 WrapperConfig
)

环境变量键名约定。Worker spawn wrapper 时写入这些变量。

View Source
const EventJavaExit = "java_exit"

EventJavaExit 是 ExitEvent.Event 的取值:被托管进程非正常退出(FR-313)。 事件字段留作区分未来其他 wrapper 事件,Worker 侧按值过滤、未知事件忽略。

View Source
const HeaderSize = 8
View Source
const MaxPayloadSize = 4 * 1024 * 1024 // 4MB

Variables

This section is empty.

Functions

func Dial

func Dial(addr string) (net.Conn, error)

Dial 拨号到指定地址。

func ExitInfo

func ExitInfo(ps *os.ProcessState) (exitCode int, signal string)

ExitInfo 从进程退出状态提取退出码与信号名(FR-313)。 ps 为 nil(Wait 出错且无退出状态)时退出码取 -1。信号仅 Unix 有意义:被信号终止时 返回 syscall.Signal 的字符串形式(如 killed/terminated);Windows 的 WaitStatus Signaled() 恒为 false,信号恒为空(与 spec「Windows 信号留空」一致)。

func IgnoreBrokenPipe

func IgnoreBrokenPipe()

IgnoreBrokenPipe 让 wrapper 进程忽略 SIGPIPE(Unix)。

wrapper 的 stdout/stderr 由父 Worker 设为 OS 管道(见 process/daemon.go 的 newSlogWriter: 非 *os.File 的 io.Writer 会让 exec 建管道、读端留在 Worker 内)。Worker 重启/崩溃后管道读端 关闭,wrapper 下一次日志写 fd 1/2 会触发 SIGPIPE——Go 运行时对 fd 1/2 的 SIGPIPE 默认**终止 进程**,从而拖死本应存活的 daemon 游戏服(见 ADR-003 守护进程 Wrapper、FR-341)。

忽略后,写已断的 fd 返回 EPIPE(由 slog 静默丢弃该行)而不终止进程;wrapper 存活,等待 Worker 经 Unix Socket 重连接管。仅影响 wrapper 子进程自身的日志流,不影响游戏服 stdin/stdout(走独立 管道,随 socket 重连恢复)。

func IsPIDAlive

func IsPIDAlive(pid int) bool

IsPIDAlive 在 Linux/macOS 上用 signal 0 探测进程是否存在(不实际发送信号)。

func KillPIDTree

func KillPIDTree(pid int) error

KillPIDTree 按 PID 强杀整棵进程树(FR-325 接管兜底:只有 PID 记录、无 *exec.Cmd 句柄)。 与 killProcessTree 同源:杀 pid 所在进程组(负 pgid,SIGKILL),取不到 pgid 时回退杀单进程。

func Listen

func Listen(addr string) (net.Listener, error)

Listen 在指定地址监听,返回平台无关的 net.Listener。 具体传输(Unix Socket / Named Pipe)由平台文件实现。

func PIDFileName

func PIDFileName(pidDir, instanceUUID string) string

PIDFileName 返回实例 PID 文件路径。

func ParseAutoRestart

func ParseAutoRestart(s string) bool

ParseAutoRestart 辅助从字符串解析布尔(供环境变量传递)。

func RemoveSocket

func RemoveSocket(addr string)

RemoveSocket 删除 Unix Socket 文件,忽略不存在错误。

func Run

func Run(cfg WrapperConfig) error

Run 启动 wrapper 主循环,阻塞直到收到 stop/kill 或 Java 永久退出且无自动重启。

func RunWithReady

func RunWithReady(cfg WrapperConfig, ready chan<- struct{}) error

RunWithReady 同 Run,并在 wrapper 监听就绪后向 ready 发送信号(非阻塞)。 ready 为 nil 时忽略。供测试/集成方等待 wrapper 可被拨号后再连接,消除竞态。

func SocketAddr

func SocketAddr(pidDir, instanceUUID string) string

SocketAddr 为实例生成跨平台的通信地址。 Linux/macOS:Unix Socket 文件路径(<pidDir>/<uuid>.sock)。 Windows:Named Pipe 名称(\\.\pipe\jianmanager-<uuid>)。 返回的地址可直接传给 Listen/Dial。

func WaitForPriorExit

func WaitForPriorExit(pidDir, uuid string)

WaitForPriorExit 在(重新)启动 daemon 实例前,按 PID 文件等待上一代 wrapper/Java 进程完全退出。

背景:快速 stop→start 时,旧实例可能仍在优雅退出,其 Java 仍占着监听端口(如 25566)、 其 wrapper 仍占着通信 socket。此时直接 spawn 新 wrapper/Java 会因端口/地址冲突崩溃 (worker 日志可见 `wrapper 进程退出 err="exit status 1"`)。本函数把这一竞态收敛掉。

语义:PID 文件不存在(上一代已自清理)即视为已退出,立即返回;wrapper 与 Java PID 均不存活 时返回;超时后尽力而为返回(不无限期阻塞启动,避免旧进程卡死时永远起不来)。

Types

type Channel

type Channel uint16

Channel 帧通道。

const (
	ChannelStdin   Channel = 0
	ChannelStdout  Channel = 1
	ChannelStderr  Channel = 2
	ChannelControl Channel = 3
)

type ExitEvent

type ExitEvent struct {
	// Event 事件类型,恒为 EventJavaExit。
	Event string `json:"event"`
	// ExitCode 进程退出码;无法获知时为 -1。
	ExitCode int `json:"exit_code"`
	// Signal 终止信号名(Unix,如 killed/terminated);Windows / 非信号退出为空。
	Signal string `json:"signal,omitempty"`
	// DurationMs 本次运行时长(毫秒)。
	DurationMs int64 `json:"duration_ms"`
}

ExitEvent 是 wrapper 检测到被托管进程非正常退出时,经控制通道(ChannelControl + TypeEvent)上抛给 Worker 的事件负载(JSON,FR-313)。daemon 模式下进程由 wrapper 直接托管,退出码/信号只有 wrapper 能拿到,须经此事件转交 Worker 组装崩溃快照。

func DecodeExitEvent

func DecodeExitEvent(payload []byte) (ExitEvent, bool)

DecodeExitEvent 从事件帧负载解析退出事件;非 java_exit 事件返回 ok=false(忽略)。

type Flags

type Flags uint8

Flags 帧标志位。

const (
	FlagCompressed Flags = 0x01 // bit0: zlib 压缩
)

type Frame

type Frame struct {
	Header
	Payload []byte
}

Frame 完整帧。

func Decode

func Decode(r io.Reader) (*Frame, error)

Decode 从 reader 解码读取帧。

func EncodeExitEventFrame

func EncodeExitEventFrame(ev ExitEvent) (*Frame, error)

EncodeExitEventFrame 把退出事件编码为控制通道事件帧。

func (*Frame) Encode

func (f *Frame) Encode(w io.Writer) error

Encode 将帧编码写入 writer。

type Header struct {
	Channel Channel // 2 bytes
	Type    Type    // 1 byte
	Flags   Flags   // 1 byte
	Length  uint32  // 4 bytes
}

Header 帧头 (8 字节)。

type InstanceState

type InstanceState string

InstanceState 复用 process 包的状态语义(此处独立定义避免循环依赖)。

const (
	StateStopped  InstanceState = "STOPPED"
	StateStarting InstanceState = "STARTING"
	StateRunning  InstanceState = "RUNNING"
	StateStopping InstanceState = "STOPPING"
	StateCrashed  InstanceState = "CRASHED"
)

type PIDFile

type PIDFile struct {
	// contains filtered or unexported fields
}

PIDFile PID 文件管理。 旧版只存裸 PID 数字,新版存 JSON(PIDRecord)。Read 同时兼容两种格式。

func NewPIDFile

func NewPIDFile(path string) *PIDFile

NewPIDFile 创建 PID 文件管理器。

func (*PIDFile) IsProcessAlive

func (p *PIDFile) IsProcessAlive() bool

IsProcessAlive 检查进程是否存活。

func (*PIDFile) Path

func (p *PIDFile) Path() string

Path 返回 PID 文件路径。

func (*PIDFile) Read

func (p *PIDFile) Read() (int, error)

Read 读取 PID 文件中的 PID(优先返回 wrapper pid)。

func (*PIDFile) ReadRecord

func (p *PIDFile) ReadRecord() (*PIDRecord, error)

ReadRecord 读取完整恢复记录。

func (*PIDFile) Remove

func (p *PIDFile) Remove() error

Remove 删除 PID 文件。

func (*PIDFile) Write

func (p *PIDFile) Write(pid int) error

Write 写入 PID 文件(仅 wrapper pid,旧版兼容)。

func (*PIDFile) WriteRecord

func (p *PIDFile) WriteRecord(rec PIDRecord) error

WriteRecord 写入完整恢复记录(JSON)。

type PIDRecord

type PIDRecord struct {
	WrapperPID   int    `json:"wrapper_pid"`
	JavaPID      int    `json:"java_pid"`
	SocketAddr   string `json:"socket_addr"` // Unix Socket 路径或 Named Pipe 名称
	InstanceUUID string `json:"instance_uuid"`
	WorkDir      string `json:"work_dir"`             // 实例工作目录,供 Worker 重启恢复后做文件/配置操作
	ProbePort    int    `json:"probe_port,omitempty"` // ServerProbe /metrics 端口,供 Worker 重启恢复后心跳继续自采(FR-060)
}

PIDRecord 记录 daemon wrapper 的恢复信息。 Worker 重启后读取此文件:wrapper pid 存活则 reconnect socket 恢复管理, 否则清理文件。java pid 用于诊断/展示。

type RingBuffer

type RingBuffer struct {
	// contains filtered or unexported fields
}

RingBuffer 环形缓冲区,用于存储最近的输出。 支持多个观察者同时读取。

func NewRingBuffer

func NewRingBuffer(size int) *RingBuffer

NewRingBuffer 创建指定大小的环形缓冲区。

func (*RingBuffer) Len

func (r *RingBuffer) Len() int

Len 返回缓冲区中的数据长度。

func (*RingBuffer) ReadAll

func (r *RingBuffer) ReadAll() []byte

ReadAll 读取缓冲区中的所有数据(按写入顺序)。

func (*RingBuffer) Reset

func (r *RingBuffer) Reset()

Reset 清空缓冲区。

func (*RingBuffer) Write

func (r *RingBuffer) Write(data []byte)

Write 写入数据到环形缓冲区。

type Type

type Type uint8

Type 帧类型。

const (
	TypeData      Type = 0x01
	TypeCommand   Type = 0x02
	TypeResponse  Type = 0x03
	TypeHeartbeat Type = 0x04
	// TypeEvent 事件帧(wrapper→Worker 单向,ChannelControl,payload=JSON,FR-313)。
	// 版本互不炸:老 Worker 的 readLoop 只消费 stdout/stderr 通道、忽略未知帧;
	// 老 wrapper 从不发事件帧,新 Worker 收不到即无快照,均不影响既有链路。
	TypeEvent Type = 0x05
)

type Wrapper

type Wrapper struct {
	// contains filtered or unexported fields
}

Wrapper 是 daemon wrapper 子进程的运行体。 它作为 Java 进程的父进程,负责:启动/重启 Java、监听 socket、 与 Worker 双向帧通信(转发 stdio + 接收控制命令)、维护 PID 文件。 参见 ADR-003: 守护进程 Wrapper 模式。

type WrapperConfig

type WrapperConfig struct {
	InstanceUUID string `json:"instance_uuid"`
	StartCommand string `json:"start_command"`
	// StopCommand 优雅停止时写入进程 stdin 的命令(不含换行)。
	// 由 Control Plane 按实例角色派生(MC 后端用 stop,代理用 end)。
	// 为空时 wrapper 回退到 MC 的 "stop",保证旧实例/恢复路径行为不变。
	StopCommand  string            `json:"stop_command,omitempty"`
	WorkDir      string            `json:"work_dir"`
	EnvVars      map[string]string `json:"env_vars"`
	JavaHome     string            `json:"java_home,omitempty"`
	JDKBinPath   string            `json:"jdk_bin_path,omitempty"`
	AutoRestart  bool              `json:"auto_restart"`
	PIDDir       string            `json:"pid_dir"`
	StartTimeout time.Duration     `json:"start_timeout"` // Java 启动到首字节输出的等待(0=不限)
	// ProbePort 透传到 PID 记录,使 Worker 重启恢复后心跳继续自采该实例 ServerProbe 指标(FR-060)。
	ProbePort int `json:"probe_port,omitempty"`
	// GracefulStopTimeoutSeconds 优雅停止后等待进程自行退出的上限(秒,CP 从平台设置
	// graceful_stop.timeout 取生效值后于启动时下发,FR-063)。>0 时 wrapper 用它做超时强杀兜底;
	// 0=未指定,回退环境变量/默认。值在启动时定型,故对设置变更后「新启动」的实例生效。
	GracefulStopTimeoutSeconds int `json:"graceful_stop_timeout_seconds,omitempty"`
}

WrapperConfig 是 daemon wrapper 子进程的启动配置。 通过环境变量从 Worker 传递给 wrapper 子进程(避免命令行长度/转义问题)。 WrapperConfig 是 daemon wrapper 子进程的启动配置。 通过环境变量从 Worker 传递给 wrapper 子进程(避免命令行长度/转义问题)。

func ParseWrapperConfigFromEnv

func ParseWrapperConfigFromEnv() (WrapperConfig, error)

ParseWrapperConfigFromEnv 从环境变量解析 wrapper 配置。 供 cmd/worker 的 daemon 子命令调用。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL