# process_host **Repository Path**: chmodke/process_host ## Basic Information - **Project Name**: process_host - **Description**: Windows 进程守护、cron 定时调度一体化工具。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-12 - **Last Updated**: 2026-11-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Process Host [![Go Version](https://img.shields.io/badge/Go-1.20+-00ADD8?style=flat&logo=go)](https://go.dev/) [![Platform](https://img.shields.io/badge/Platform-Windows-0078D6?style=flat&logo=windows)](https://www.microsoft.com/windows) [![License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) Process Host 是一个 Windows 平台下的进程托管工具,采用守护进程 + 管理客户端的架构,支持将任意可执行程序作为 Windows 服务托管运行,提供自动重启、日志管理、独立配置等功能。 > 注意:源代码均由DeepSeek生成,请勿直接插入工作交付件。 ## ✨ 特性 - **服务化运行**:守护进程作为 Windows 服务运行,开机自启,无需用户登录 - **多进程托管**:同时管理多个可执行程序,每个进程独立配置 - **自动重启**:进程崩溃后自动重启,可配置重启延迟 - **客户端分离**:守护进程与管理客户端独立,通过 TCP 通信 - **独立配置**:每个托管进程拥有独立的 YAML 配置文件 - **共享凭据库**:账号密码集中加密保存,进程/任务通过 `credential` 引用,避免重复配置 - **表格化展示**:CLI 以清晰的表格展示所有进程状态 - **定时任务**:`krond` 按 cron 表达式周期执行脚本,`kron` 通过本地 TCP 管理任务 - **跨平台潜力**:核心逻辑可扩展至 Linux/macOS ## 🏗️ 架构 ``` ┌─────────────────────────────────────────────────────────────┐ │ Windows Service (SCM) │ └─────────────────────────┬───────────────────────────────────┘ │ 管理 ▼ ┌─────────────────────────────────────────────────────────────┐ │ 守护进程 (daemon) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ API Server │ │ Manager │ │ 配置加载器 │ │ │ │ (TCP :9527) │ │ │ │ (processes/*.yaml) │ │ │ └──────┬──────┘ └──────┬──────┘ └─────────────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 托管进程 (Managed Processes) │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ java_app │ │ python │ │ nginx │ ... │ │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ▲ │ TCP (JSON) │ ┌─────────────────────────┴───────────────────────────────────┐ │ 管理客户端 (ph_ctl) │ │ list | start | stop | restart | add | remove │ └─────────────────────────────────────────────────────────────┘ ``` ## 📦 安装 ### 从源码编译 ```bash # 克隆仓库 git clone https://gitee.com/chmodke/process_host.git cd process-host # 安装依赖 go mod download # 编译守护进程 cd phd go build -o phd.exe # 编译管理客户端 cd ../ph_ctl go build -o ph_ctl.exe # 编译调度进程与调度客户端 cd ../krond go build -o krond.exe cd ../kron go build -o kron.exe # 编译日志清理工具 cd ../logclean go build -o logclean.exe ``` 也可直接运行 `powershell -ExecutionPolicy Bypass -File build.ps1` 打包全部程序。打包生成的 `phd.zip` 包含五个 exe、`phd.yaml`、`krond.yaml`、空白的 `credentials.yaml` 模板、`processes/` 与 `jobs/`。未指定 `-Version` 时按 `git describe --tags --dirty` 自动生成并追加构建时间戳 `yyyyMMddHHmmss`(无标签/无 git 时为 `dev-<时间戳>`,否则为 `<描述>-<时间戳>`),也可显式指定:`build.ps1 -Version v1.0.0`(不追加时间戳)。五个程序均支持 `--version` 查看版本(含 Git 提交号与工作区是否脏)。 ### 安装 Windows 服务 以**管理员身份**运行命令提示符或 PowerShell: ```cmd # 创建服务 sc create ProcessHost binPath= "C:\path\to\phd.exe -config C:\path\to\phd.yaml" start= auto # 启动服务 sc start ProcessHost ``` ## 🚀 快速开始 ### 1. 创建守护进程配置文件 `phd.yaml`: ```yaml listen_port: 9527 # API 监听端口(IP 固定为 127.0.0.1,不支持外部访问) config_dir: "C:\\path\\to\\processes" # 托管进程配置目录,建议配置为绝对路径 log_dir: "C:\\path\\to\\logs" # 日志目录,建议配置为绝对路径 credentials_file: "C:\\ProgramData\\ProcessHost\\credentials.yaml" # 共享凭据文件(可选) ``` > 目录重命名:托管进程配置目录已由 `configs/` 改为 `processes/`。升级时请同步修改 `phd.yaml` 的 `config_dir`。 ### 2. 创建托管进程配置文件 在 `processes/` 目录下创建 `my_app.yaml`: ```yaml name: "my_app" enabled: true path: "C:\\path\\to\\your\\app.exe" args: ["-p", "8080"] workdir: "C:\\path\\to\\your" env: APP_ENV: "production" credential: "my_svc" # 先执行 ph_ctl cred add my_svc .\ph_test auto_restart: true restart_delay_sec: 10 ``` > 也可以继续使用旧写法 `user`/`password`,但多个进程/任务共用账号时推荐使用共享凭据库。 ### 3. 使用 CLI 管理 ```cmd # 查看所有进程状态 ph_ctl.exe list # 启动进程 ph_ctl.exe start my_app # 停止进程 ph_ctl.exe stop my_app # 重新读取进程配置文件(不重启运行中的进程,新配置在下次启动/重启时生效) ph_ctl.exe reload my_app # 停止/启动全部进程(start --all 只启动 enabled=true 的进程) ph_ctl.exe stop --all ph_ctl.exe start --all # 禁用/启用进程(禁用不会停止正在运行的进程) ph_ctl.exe disable my_app ph_ctl.exe enable my_app ph_ctl.exe disable --all ph_ctl.exe enable --all # 注册新进程 ph_ctl.exe add C:\processes\another_app.yaml # 注销进程 ph_ctl.exe remove my_app ``` ## 📋 CLI 命令参考 | 命令 | 说明 | 示例 | |------|------|------| | `list` | 列出所有托管进程状态(表格形式) | `ph_ctl list` | | `status ` | 查看指定进程详细状态 | `ph_ctl status my_app` | | `start ` | 启动指定进程 | `ph_ctl start my_app` | | `stop ` | 停止指定进程 | `ph_ctl stop my_app` | | `restart ` | 重启指定进程 | `ph_ctl restart my_app` | | `reload ` | 重新读取该进程的配置文件并更新内存定义(不重启运行中的进程) | `ph_ctl reload my_app` | | `stop --all` | 停止所有托管进程 | `ph_ctl stop --all` | | `start --all` | 启动所有已启用的进程(已运行的跳过) | `ph_ctl start --all` | | `enable ` | 启用进程(仅随 phd 启动自动拉起,不立即启动) | `ph_ctl enable my_app` | | `disable ` | 禁用进程(不停止正在运行的进程) | `ph_ctl disable my_app` | | `enable --all` | 启用所有托管进程 | `ph_ctl enable --all` | | `disable --all` | 禁用所有托管进程 | `ph_ctl disable --all` | | `add ` | 注册新进程(支持 YAML/JSON) | `ph_ctl add C:\my_app.yaml` | | `remove ` | 注销并删除进程配置 | `ph_ctl remove my_app` | | `cred list` | 列出所有凭据(仅名称和账户) | `ph_ctl cred list` | | `cred add ` | 新增或更新凭据(交互输入一次密码,服务端校验账户) | `ph_ctl cred add svc_a .\appuser` | | `cred remove ` | 删除凭据 | `ph_ctl cred remove svc_a` | **选项**: - `--addr string` - 守护进程地址(默认 `127.0.0.1:9527`),可放在动作之前或之后,例如 `ph_ctl list --addr 127.0.0.1:9527` - `--all` - 对 `start`/`stop`/`enable`/`disable` 作用于全部进程,不能与进程名同时使用,例如 `ph_ctl start --all` - `--version` - 显示版本信息(`phd`、`ph_ctl`、`krond`、`kron`、`logclean` 均支持) ## 🔐 共享凭据库 多个进程/任务使用同一 Windows 账号时,把账号密码集中到共享凭据库,配置只写 `credential: `。 - 凭据文件默认 `C:\ProgramData\ProcessHost\credentials.yaml`,可用 `phd.yaml` / `krond.yaml` 的 `credentials_file` 覆盖;两个守护进程必须指向同一文件。 - 密码使用 Windows DPAPI 机器级加密保存;文件权限为宽松 ACL(`SYSTEM`/`Administrators` 完全控制、`Users` 修改),以支持以普通账户运行的 krond。 - `ph_ctl cred` 与 `kron cred` 两套命令相互独立,共享同一凭据文件;任一守护进程运行即可管理凭据,无需另一个守护进程在线。 ```cmd # 通过 phd 管理 ph_ctl cred add svc_app .\ph_test ph_ctl cred list ph_ctl cred remove svc_app # 通过 krond 管理(即使 phd 未运行) kron cred add svc_jobs .\svcuser kron cred list kron cred remove svc_jobs ``` 进程/任务配置中引用: ```yaml credential: "svc_app" # 与 user/password 二选一 ``` - 修改凭据后,进程下次启动、任务下次执行自动使用新密码;已运行实例不受影响。 - 凭据与机器 DPAPI 密钥绑定:换机、重装或 DPAPI 密钥重置后需重新录入;凭据文件必须放在本地磁盘,不要放网络共享。 - 旧的 `user`/`password` 内联写法仍兼容,但不再推荐。 - 凭据文件对本机普通用户可读写(为支持普通账户运行的 krond),请确保机器本身可信。 **添加凭据时的校验**: - `cred add` 只提示输入一次密码(不再二次确认),服务端用 Windows `LogonUser` 以批处理/交互式登录方式校验账户,并校验返回令牌的用户身份(与进程启动路径一致)。 - 校验明确失败(本地账户用户名或密码错误、账户不存在/禁用/锁定/过期、密码过期等)时拒绝保存并返回错误;错误密码会计入 Windows 失败登录次数,可能触发账户锁定,请谨慎重试。 - 因环境原因无法校验时(例如目标账户是 gMSA 需要 `SeTcbPrivilege`/通常需 LocalSystem、域控不可达、账户缺少“作为批处理作业登录”/“允许本地登录”权限、校验超时),凭据仍会保存,CLI 在 stderr 输出 `Warning:` 说明原因。域账户的 1326 无法区分密码错误与域控不可达,同样按“保存并警告”处理。 - 普通本地/域账户的校验不要求服务端以 SYSTEM 运行;只有 gMSA 等特殊账户需要 LocalSystem(`SeTcbPrivilege`)。 ## 📁 配置文件格式 ### 守护进程配置 (`phd.yaml`) | 字段 | 类型 | 说明 | 默认值 | |------|------|------|--------| | `listen_port` | int | API 服务监听端口(强制监听 `127.0.0.1`) | `9527` | | `config_dir` | string | 托管进程配置目录 | `./processes` | | `log_dir` | string | 日志输出目录 | `C:\ProgramData\ProcessHost\logs` | | `credentials_file` | string | 共享凭据文件路径 | `C:\ProgramData\ProcessHost\credentials.yaml` | ### 托管进程配置 (`*.yaml`) | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `name` | string | 否 | 进程名称,默认使用文件名 | | `enabled` | bool | 否 | 是否随守护进程自动启动 | | `path` | string | **是** | 可执行文件绝对路径 | | `args` | []string | 否 | 启动参数 | | `workdir` | string | 否 | 工作目录 | | `env` | map[string]string | 否 | 环境变量 | | `credential` | string | 否 | 引用共享凭据库中的凭据名称;与 `user`/`password` 二选一 | | `user` | string | 否 | 旧写法:运行账户(`DOMAIN\user`、`.\user`、`user@domain`);推荐改用 `credential` | | `password` | string | 否 | 旧写法:账户密码(明文保存于配置文件,不推荐) | | `auto_restart` | bool | 否 | 崩溃后是否自动重启 | | `restart_delay_sec` | int | 否 | 重启延迟(秒) | > **安全提示**:推荐使用共享凭据库(`credential`),密码以 DPAPI 机器级加密保存。若继续使用内联 `password`,它会以明文保存在 `processes/*.yaml` 中,并在 `add` 时明文经 TCP 传输。`cred add` 的密码同样经 loopback TCP 明文传输,因此凭据管理动作仅接受本机连接。凭据文件对本地普通用户可读写(为支持普通账户运行的 krond),请确保机器本身可信。 > **运行账户要求**:以指定用户运行依赖 `CreateProcessAsUser`,守护进程需以 LocalSystem 服务方式运行(或具备 `SeAssignPrimaryTokenPrivilege` / `SeIncreaseQuotaPrivilege`)。普通管理员前台调试会因缺少特权报错 1314。指定用户时环境变量由该用户的环境块生成,但不会加载该用户的 HKCU 注册表配置文件。 ## 🗂️ 项目结构 ``` process-host/ ├── go.mod ├── go.sum ├── README.md ├── phd/ # phd 守护进程 │ ├── main.go # 入口 │ ├── service.go # Windows 服务逻辑 │ ├── manager.go # 进程管理器 │ └── api.go # TCP API 服务 ├── ph_ctl/ │ └── main.go # ph_ctl 管理客户端 ├── krond/ # 定时任务调度进程 ├── kron/ │ └── main.go # 定时任务管理客户端 ├── logclean/ │ └── main.go # 日志老化清理工具 ├── internal/ │ ├── console/ # CLI 密码输入 │ ├── credstore/ # DPAPI 共享凭据库 │ ├── cron/ # 5 字段 cron 解析 │ ├── logclean/ # 日志老化与孤儿目录清理 │ ├── logfile/ # 按日切换的日志写入器 │ ├── version/ # 构建时注入的版本信息 │ └── winproc/ # 共享的进程启动 / run-as 逻辑 ├── protocol/ │ └── protocol.go # 共享通信协议 ├── processes/ # 托管进程配置目录 │ ├── java_app.yaml │ └── krond.yaml ├── jobs/ # 定时任务配置目录 │ ├── example.yaml │ └── logclean.yaml ├── phd.yaml # 守护进程配置 ├── krond.yaml # 调度进程配置 └── build.ps1 # 构建与打包脚本 ``` ## 🔧 开发调试 ### 非服务模式运行守护进程 ```bash cd phd go run . -config phd.yaml # 或直接运行编译后的程序 .\phd.exe -config phd.yaml ``` 按 `Ctrl+C` 优雅退出。 ### 查看日志 所有日志按本地日期每天一个文件,文件名格式为 `<名称>_YYYY-MM-DD.log`(当天有写入时才创建)。 phd 的 `log_dir` 下: - `phd_run_YYYY-MM-DD.log` - 守护进程自身运行日志 - `<进程名>/schedule_YYYY-MM-DD.log` - 各托管进程的启停与退出记录 - `<进程名>/stdout_YYYY-MM-DD.log` - 子进程标准输出(原样字节,不转码) - `<进程名>/stderr_YYYY-MM-DD.log` - 子进程标准错误(原样字节,不转码) krond 的 `log_dir` 下: - `krond_run_YYYY-MM-DD.log` - 调度进程自身运行日志 - `<任务名>/schedule_YYYY-MM-DD.log` - 开始/结束标记、退出码与耗时 - `<任务名>/stdout_YYYY-MM-DD.log` - 脚本标准输出(原样字节,不转码) - `<任务名>/stderr_YYYY-MM-DD.log` - 脚本标准错误(原样字节,不转码) `schedule` 与运行日志固定为 UTF-8;`stdout`/`stderr` 保留子进程原始编码(GBK 程序需按 CP936 查看)。旧版日志文件(`phd.log`、`process.log`、`krond.log`、`<任务名>/YYYY-MM-DD.log`)不会自动迁移,`logclean` 也不会删除它们(只识别当前命名格式)。当前格式日志的保留期清理见“日志老化清理”章节。 ## ⏰ 定时任务(krond + kron) `krond` 是定时任务调度进程,由 phd 作为普通托管进程启动;`kron` 通过本地 TCP 直接管理 krond。 ``` phd (127.0.0.1:9527) ──托管── krond (127.0.0.1:9528) ◀── kron │ └── 按 cron 计划执行脚本 ``` ### 1. 由 phd 托管 krond 编辑 `processes/krond.yaml`,把 `path`、`args`、`workdir` 改成实际绝对路径,将 `enabled` 改为 `true`,重启 phd(或先 `ph_ctl add processes/krond.yaml` 再启动)。建议设置 `workdir`,这样 `krond.yaml` 中的相对 `jobs_dir` 才能正确解析。 `krond.yaml`: ```yaml listen_port: 9528 # API 监听端口(IP 固定为 127.0.0.1) jobs_dir: "jobs" # 任务配置目录,相对 krond 工作目录 log_dir: "C:\\path\\to\\logs\\jobs" # 省略则默认 C:\ProgramData\ProcessHost\logs\jobs credentials_file: "C:\\ProgramData\\ProcessHost\\credentials.yaml" # 必须与 phd.yaml 一致 ``` ### 2. 任务配置 任务统一存放在 `jobs/` 目录(`jobs_dir`),也可通过 `kron add` 注册。示例 `jobs/backup.yaml`: ```yaml name: "backup" enabled: true schedule: "0 2 * * *" # 每天 02:00 path: "C:\\Windows\\System32\\cmd.exe" # 必需:显式解释器 args: ["/c", "C:\\scripts\\backup.bat"] # 脚本路径放在参数中 workdir: "C:\\scripts" env: BACKUP_DIR: "D:\\backup" # credential: "svc_jobs" # 引用共享凭据库(与 user/password 二选一) # user: ".\\svcuser" # 旧写法,不推荐 # password: "secret" ``` - `schedule` 为标准 5 字段 cron(分 时 日 月 周),支持 `*`、`a-b`、`*/n`、`a-b/n`、逗号列举;最小粒度 1 分钟,按本地时间执行。 - 脚本必须显式指定解释器(`cmd.exe /c`、`powershell.exe -NoProfile -File` 等),不会自动包装 `.bat`/`.ps1`。 - `auto_restart` / `restart_delay_sec` 对定时任务无效。 - 任务名称允许中文,但不能包含 `\ / : * ? " < > |`,不能是 Windows 保留名(CON、COM1 等),长度不超过 64 字符。 ### 3. kron 命令 | 命令 | 说明 | |------|------| | `kron list` | 列出全部任务及下次/上次执行状态 | | `kron show ` | 查看任务配置与运行状态 | | `kron add ` | 注册任务(支持 YAML/JSON) | | `kron remove ` | 删除任务配置,并终止正在运行的实例 | | `kron enable ` | 启用调度并持久化 | | `kron disable ` | 禁用调度(不中断正在运行的实例) | | `kron reload ` | 重新读取任务配置文件并立即重算下次执行时间(不中断运行中的实例) | | `kron cred list` | 列出所有凭据(仅名称和账户) | | `kron cred add ` | 新增或更新凭据(交互输入一次密码,服务端校验账户) | | `kron cred remove ` | 删除凭据 | `kron` 的 `--addr`(默认 `127.0.0.1:9528`)可放在动作之前或之后,例如 `kron list --addr 127.0.0.1:9528`;`--version` 显示版本信息。 ### 4. 调度语义与执行日志 - 同一任务上次执行未结束时,本次触发**跳过**并在 `krond_run_YYYY-MM-DD.log` 记录告警。 - krond 停机期间错过的触发**不补跑**。 - 运行时状态(下次执行、上次退出码、耗时等)仅保存在内存,krond 重启后清空;执行历史以日志文件为准。 - 每个任务每天三个日志:`/<任务名>/{schedule,stdout,stderr}_YYYY-MM-DD.log`;`schedule` 含开始/结束标记、退出码与耗时,stdout/stderr 原样保存。 - 修改 `jobs/*.yaml` 后执行 `kron reload ` 使配置生效(不重启 krond,正在执行的实例不受影响);新增/删除任务请使用 `kron add` / `kron remove`。krond 不监听文件变化。 - 使用内联 `password` 时密码明文保存在任务 YAML,并明文经本地 TCP 传输;推荐改用 `credential`。 - phd 停止 krond 时是硬终止,正在执行的脚本子进程可能残留。 ## 🧹 日志老化清理(logclean) `logclean` 是独立的一次性清理程序,建议由 krond 每天凌晨 01:00 托管执行,删除过期日志文件并清理已移除进程/任务的日志目录。 ```cmd logclean [--phd-addr 127.0.0.1:9527] [--kron-addr 127.0.0.1:9528] <日志根目录> <保留天数> logclean C:\ProgramData\ProcessHost\logs 30 ``` - 保留期为整数天数(最小 1),保留今天在内的 N 个日历日;只处理 `schedule`/`stdout`/`stderr`/`phd_run`/`krond_run` 的 `<名称>_YYYY-MM-DD.log`,其他文件(含旧版日志)不删除。 - 日志根目录必须直接包含 `phd_run_*.log` 或 `krond_run_*.log`,且不能是盘符根;这是防止误指向 `C:\Windows` 等目录的保护。 - 支持嵌套根:phd 根目录下的 `jobs/`(krond 默认日志目录)会被识别为第二层日志根,再向下一层处理任务目录。 - **孤儿目录删除**:仅当 phd(`--phd-addr`)与 krond(`--kron-addr`)的 list 接口都成功、且目录名不在“phd 进程名 ∪ kron 任务名”中时,才删除该目录;任一接口不可达则本轮只删除过期文件。配置加载失败而被跳过的进程/任务不在 list 中,其日志目录会被视为孤儿删除。 - 仅删除“纯日志目录”(目录内全部是可识别日志文件且至少一个);空目录、含其他文件或子目录、符号链接/junction 一律不动,且不会删除日志根本身。 - 正被进程写入的日志文件(Windows 共享冲突)计入 skipped,不视为失败,下一轮会重试。 - 退出码:0 成功(含降级模式)、1 运行错误、2 参数错误。 由 krond 托管时,将 `logclean.exe` 放在可访问的绝对路径,并注册任务(样例见 `jobs/logclean.yaml`): ```yaml name: "logclean" enabled: true schedule: "0 1 * * *" path: "C:\\ProgramData\\ProcessHost\\logclean.exe" args: ["C:\\ProgramData\\ProcessHost\\logs", "30"] workdir: "C:\\ProgramData\\ProcessHost" ``` ## ❓ 常见问题 ### Q: 服务启动失败,报错 1053? A: 通常是配置文件路径问题或依赖缺失。请检查: 1. `phd.yaml` 中的路径是否正确 2. 托管进程的 `path` 是否使用绝对路径 3. 工作目录是否有写入权限 ### Q: CLI 无法连接守护进程? A: 确保: 1. 守护进程服务已启动 2. 端口未被其他程序占用(守护进程只监听 `127.0.0.1`) 3. `--addr` 使用 `127.0.0.1:`,端口与 `phd.yaml` 一致 ### Q: 进程启动后立即退出? A: 查看守护进程日志,通常是因为: 1. 可执行文件路径错误 2. 缺少依赖的 DLL 或环境变量 3. 工作目录权限不足 ## 🤝 贡献 欢迎提交 Issue 和 Pull Request! ## 📄 许可证 MIT License - 详见 [LICENSE](LICENSE) 文件。