跳到主要内容

将 Anyy 作为常驻服务运行

Anyy 是一个常驻、本地优先的个人助理。你既可以直接在终端里运行它,也可以 让它始终在线,从而在没有打开任何终端时仍能接收消息、执行计划任务。本页是把 Anyy 作为常驻服务运行、以及管理网关生命周期的权威参考。

如果你还没有安装 Anyy,请先阅读安装

前台运行 vs 常驻运行

Anyy 有两种运行方式:

  • 前台运行 —— 你在终端里运行 anyy。TUI 可能仅为当前会话启动一个临时的 进程内网关。关闭终端后网关随之停止,于是入站消息和计划任务都不再被处理。这非常 适合体验功能和一次性的工作。
  • 常驻运行 —— 一个轻量的后台服务让网关在重启和注销后依然运行。一旦你接入了消息 渠道,或依赖提醒、cron、心跳等功能,就需要这种方式。即便没有打开任何终端,你的 助理也能保持在线、随时可达。

安装 Anyy 本身绝不会自行启动后台服务,而一条普通的 anyy 命令在未经 询问的情况下也绝不会安装服务。转为常驻是你通过 anyy gateway start 做出的 明确选择(或者在 anyy setup 过程中接受相应提示)。

需要常驻网关的功能:

  • 在没有打开终端时接收渠道消息(例如微信)
  • 由网关托管的 cron、提醒、心跳和后台任务
  • 任何期望运行时持续可用的客户端

网关生命周期

网关(gateway) 是常驻运行时,负责托管渠道、后台任务,以及其他 Anyy 命令 所对接的本地 RPC 接口。Anyy 会通过一个很小的命令组替你管理它 —— 你无需直接 调用 systemctllaunchctl 或 init 脚本:

anyy gateway start [--home PATH]
anyy gateway restart [--home PATH]
anyy gateway status [--home PATH]
anyy gateway stop [--home PATH]

各子命令的作用:

  • start —— 确保后台服务已为所解析的 home 安装,然后启动它。如果服务已在运行, 则为一次空操作并报告成功。它会等待网关变为可达,然后才报告 Gateway: running
  • restart —— 刷新并重启服务。如果尚不存在服务,则安装并启动一个,而不是直接 报错。
  • stop —— 停止正在运行的服务(服务定义仍保留安装状态,因此下次开机或 start 会再次拉起它)。
  • status —— 报告服务与运行时状态,且没有任何副作用。它绝不会安装、启动或 重启任何东西。

这些命令只管理所解析 home 的 Anyy 服务,并不是一个通用的服务管理器。

服务定义始终启动同一个受监管的入口,并显式传入所解析的 home:

<home>/bin/anyy __gateway --home <home>

__gateway 是服务所使用的内部受监管运行时入口。你不要手动运行它 —— 请使用 anyy gateway start

使用哪个 home

所解析的 home 目录按以下优先级确定:

  1. --home PATH 标志
  2. ANYY_HOME 环境变量
  3. 默认值 —— 普通用户安装为 ~/.anyy,以 root 运行时为 /root/.anyy(当没有以其他方式解析出 home 时,/root/.anyy 是内置的回退值)

所有服务定义、运行时套接字、会话、状态,以及 Anyy 自身的日志都存放在这个 home 之下。

作为服务运行

anyy gateway start 会自动选择正确的宿主服务管理器:

宿主服务管理器生成的定义
macOSlaunchd 用户 代理~/Library/LaunchAgents/com.anyy.anyy.plist
systemctl 的 Linuxsystemd 用户 单元~/.config/systemd/user/anyy.service
OpenWrt(存在 /etc/openwrt_releaseprocd init 脚本/etc/init.d/anyy

在其他任何宿主上,你会得到可操作的提示,而不是悄无声息地失败:

Background service is not supported on this host yet.
Use anyy gateway start on macOS, systemd user Linux, or procd hosts.

在每个平台上推荐的方式都是 anyy gateway start —— 它会写入正确的定义、启用它、 启动它,并验证网关是否可达。下面的各平台小节展示了 Anyy 生成的确切定义(以及 用于系统级安装的随仓库附带的参考模板),让你清楚磁盘上会落下什么内容。

Linux (systemd)

在带 systemctl 的 Linux 宿主上,anyy gateway start 会在 ~/.config/systemd/user/anyy.service 安装并启用一个 systemd 用户单元。这是 默认方式,无需 root。生成的单元为:

~/.config/systemd/user/anyy.service(由 anyy gateway start 生成)
[Unit]
Description=Anyy Gateway service
After=network-online.target

[Service]
Type=simple
ExecStart="/home/you/.anyy/bin/anyy" "__gateway" "--home" "/home/you/.anyy"
WorkingDirectory=/home/you/.anyy
Restart=on-failure

[Install]
WantedBy=default.target

通过 Anyy 管理它:

anyy gateway start
anyy gateway status
anyy gateway stop

系统级(root)单元

如果某台宿主上助理应以 系统 服务、在 root 下运行(例如一台始终在线的家庭服务器), 仓库附带了一个参考 系统 单元。逐字复现自 deploy/linux/anyy.service

deploy/linux/anyy.service
[Unit]
Description=Anyy Gateway native Linux resident
Documentation=https://github.com/Mai8304/Anyy
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
Environment=ANYY_HOME=/root/.anyy
WorkingDirectory=/root/.anyy
ExecStart=/root/.anyy/bin/anyy __gateway --home /root/.anyy
ExecReload=/bin/kill -USR1 $MAINPID
Restart=always
RestartSec=3
TimeoutStopSec=60
KillSignal=SIGTERM
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
注意

安装 系统 单元需要 root。把该文件复制到 /etc/systemd/system/anyy.service,然后以 root 身份运行:

sudo systemctl daemon-reload
sudo systemctl enable --now anyy.service

该单元假定安装根目录为 /root/.anyy。它所假定的安装布局记录在 deploy/linux/README.md 中。anyy gateway 命令管理的是按用户的服务,而非这个 系统单元 —— 系统单元请使用 systemctl 管理。

macOS (launchd)

在 macOS 上,anyy gateway start 会安装一个 launchd 用户代理。仓库中 不附带任何静态 plist —— 生成的用户代理是唯一的 macOS 服务工件,而 anyy gateway start 是安装它的受支持方式。位于 ~/Library/LaunchAgents/com.anyy.anyy.plist 的生成定义为:

~/Library/LaunchAgents/com.anyy.anyy.plist(由 anyy gateway start 生成)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.anyy.anyy</string>
<key>ProgramArguments</key>
<array>
<string>/Users/you/.anyy/bin/anyy</string>
<string>__gateway</string>
<string>--home</string>
<string>/Users/you/.anyy</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>WorkingDirectory</key>
<string>/Users/you/.anyy</string>
</dict>
</plist>

RunAtLoad 让它在登录时启动,KeepAlive 在它退出时将其重新拉起。通过 Anyy 管理它 —— 你无需触碰 launchctl

anyy gateway start
anyy gateway status
anyy gateway stop
备注

这是一个按用户的 LaunchAgent,因此它在你登录期间运行。仓库不附带系统级的 LaunchDaemon。如果你需要助理在登录之前就运行,请自行编写一个包裹 anyy gateway startLaunchDaemon(这是一个手动的、由用户自行提供的示例, 而非随仓库附带的工件):

手动示例 —— 非附带工件;由你自行编写
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.anyy.boot</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/anyy</string>
<string>gateway</string>
<string>start</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

/Library/LaunchDaemons 下安装 LaunchDaemon 需要 root。

OpenWrt

OpenWrt 是一种受支持的 Linux 宿主,而不是独立的路由器产品。Anyy 通过 /etc/openwrt_release 检测到它,anyy gateway start 会在 /etc/init.d/anyy 安装一个 procd init 脚本。生成的脚本为:

/etc/init.d/anyy(由 anyy gateway start 生成)
#!/bin/sh /etc/rc.common
START=95
USE_PROCD=1

start_service() {
procd_open_instance
procd_set_param command '/root/.anyy/bin/anyy' '__gateway' '--home' '/root/.anyy'
procd_set_param respawn
procd_close_instance
}

仓库还附带了一个内容更完整的参考 init 脚本,带有显式的 respawn 上限与日志设置。逐字 复现自 deploy/openwrt/etc/init.d/anyy

deploy/openwrt/etc/init.d/anyy
#!/bin/sh /etc/rc.common

START=95
STOP=10
USE_PROCD=1

ANYY_HOME="${ANYY_HOME:-/root/.anyy}"

start_service() {
procd_open_instance
procd_set_param env ANYY_HOME="$ANYY_HOME"
procd_set_param command /root/.anyy/bin/anyy __gateway --home /root/.anyy
procd_set_param respawn 3600 5 5
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}

reload_service() {
procd_send_signal anyy
}
注意

OpenWrt 服务以 root 身份运行。请通过 Anyy 管理服务 (anyy gateway start / stop / status)。如果你要手动安装附带的参考脚本, 请把它复制到 /etc/init.d/anyy,赋予可执行权限,然后执行 /etc/init.d/anyy enable/etc/init.d/anyy start

开机自启与存活检查

服务一旦安装,每个宿主都会自动让网关保持存活:

  • macOS(launchd 用户代理) —— RunAtLoad 在登录时启动它;KeepAlive 在它退出 时重新拉起。
  • Linux(systemd 用户单元) —— WantedBy=default.targetRestart=on-failure 在它崩溃时将其重启。若要让用户服务在你注销后仍继续运行,请启用一次 lingering: sudo loginctl enable-linger $USER
  • OpenWrt(procd) —— procd_set_param respawn 会重启进程;附带的参考脚本使用 respawn 3600 5 5(仅当一小时内崩溃 5 次后才放弃)。
  • Linux 系统单元deploy/linux/anyy.service)—— Restart=always 搭配 RestartSec=3 以及 WantedBy=multi-user.target,在开机时启动它并保持运行。

网关还会运行一个心跳(heartbeat),记录自身的存活情况。用以下命令查看:

anyy heartbeat status
anyy heartbeat status --json

日志与状态

最快的健康检查是 anyy status,它会汇总网关及其各子系统:

◆ Anyy status
Gateway stopped
Profile default
...

◆ Subsystems
Gateway listener —
Cron unavailable
Heartbeat unavailable
...

若专门想看服务与运行时视图,请使用 anyy gateway status

◆ Gateway
Status not installed
Service launchd user service
Home /Users/you/.anyy
Socket /Users/you/.anyy/anyy.sock

Status 一行区分了你关心的几种情况:runningrunning manually(前台网关,但未安装 服务)、not runningnot installed,以及(当命令二进制比运行中的进程更新时) running an older Anyy —— 此时的下一步是 anyy gateway restart

各宿主的日志位置。这里有两条彼此独立的输出流:在每个宿主上,Anyy 的运行时 都会把自身的应用日志写入 <home>/logs/;而服务管理器会单独捕获进程的 stdout/stderr —— 生成的用户服务并不会把这部分输出重定向到 <home>/logs/

  • macOS / launchd —— Anyy 把自身日志写入 <home>/logs/。launchd 用户代理 会把进程的 stdout/stderr 捕获到 launchd 自己的日志位置,而非 <home>/logs/
  • Linux / systemd 用户 —— Anyy 把自身日志写入 <home>/logs/。systemd 用户 单元的 stdout/stderr 由 journald 捕获(journalctl --user -u anyy)。systemd 参考 系统 单元设置了 StandardOutput=journal / StandardError=journal,因此其 进程输出进入系统 journal(journalctl -u anyy)。
  • OpenWrt / procd —— Anyy 把自身日志写入 <home>/logs/。附带的参考脚本设置了 stdout 1 / stderr 1,因此 procd 会把进程输出转发到 syslog(logread)。

更新常驻安装

anyy update 更新程序(完整流程见更新)。当涉及常驻服务时, 更新是感知网关的:

  • 如果 Anyy 服务已安装且在运行,更新会重启它,并验证网关报告了新版本
  • 如果服务已安装但已停止,它会报告 Gateway: not running
  • 如果网关以手动方式运行、没有对应服务,它会报告 Gateway: running manually,且不会 失败
  • 如果不存在任何网关或服务,它会报告 Gateway: not installed

anyy update 绝不会安装服务 —— 这始终是一个明确的选择。如果你在 anyy gateway status 中看到版本不一致(运行中的进程比命令旧),重启网关以采用 新的构建:

anyy gateway restart

卸载服务

若要停止并移除常驻服务及程序,同时保留你的全部数据(配置、密钥、会话、日志、状态、 记忆、技能、渠道数据):

anyy uninstall --keep-data --yes

若要移除一切,包括 home 目录及全部数据:

anyy uninstall --full --yes

不带模式标志运行 anyy uninstall 会进入交互式提示;--yes / -y 标志会跳过 确认,并要求同时给出 --keep-data--full

两种模式都会在动到程序文件之前,先移除归 Anyy 所有的服务定义(launchd plist、 systemd 用户单元或 procd init 脚本),因此不会残留孤立的服务。若只想停止服务而不卸载 任何东西,请改用 anyy gateway stop

注意

如果你安装了附带的 系统 单元(deploy/linux/anyy.service)或手动的 LaunchDaemonanyy uninstall 并不会管理它 —— 那个是用 root 在 Anyy 之外 安装的。请自行将其停用,例如:sudo systemctl disable --now anyy.service