环境:Deepin 25 / X11 / DDE / fcitx5 5.1.12 / 搜狗输入法 NG(sogou-ime-ng 10.0.10.0) 说明:非官方方案,只是把"进程死了没人拉活"这件事补上;搜狗升级后路径可能变化,需自行核对。
用着用着切到搜狗就打不出中文,候选窗不出现,有时过几秒恢复,有时必须重启 fcitx5 甚至注销重登。检查进程会发现:
fcitx5
cpis-engine-service
cpis-panel-service
cpis-hotkey-service
搜狗 NG 在 fcitx5 里只是一个前端插件,真正的拼词引擎和候选窗是两个独立的 D-Bus 按需激活进程:
应用 → fcitx5 → libcpis-module-im-...so(前端插件) ├── com.cpis.engine → cpis-engine-service(拼词/词库) └── com.cpis.panel → cpis-panel-service(候选窗)
这些后端由 D-Bus 激活,没有 systemd Restart。后端异常退出后,前端插件还缓存着失效连接,于是每次按键都失败。
本机 ~/.cache/fcitx5/fcitx5.log 里的直接证据:
~/.cache/fcitx5/fcitx5.log
call method [KeyDown] error: [107] # ENOTCONN,后端 socket 已断开,按键直接丢 call method [KeyDown] error: [110] # ETIMEDOUT,后端无响应 KeyUp error: [Process com.cpis.panel exited with status 1] Failed to add match for signal ...: -107 # 候选窗彻底不出现
另外 /opt/apps/com.cpis/etc/ise.ini 里有引擎自检:
/opt/apps/com.cpis/etc/ise.ini
check_proc_status_vmrss_size = true check_proc_status_vm_rss_size_limit_kb = 512000 # 超过 500MB 自行退出
内存紧张时会更容易触发,所以这问题常常和"内存/swap 快满"一起出现。
思路:开机时由 systemd 先把三个服务拉起来。服务自己拿到 D-Bus 名字后,D-Bus 激活机制发现"名字已有 owner",就不会再产生第二个实例;进程挂了由 Restart=always 拉活。
Restart=always
~/.local/bin/ime-wait-x.sh:
~/.local/bin/ime-wait-x.sh
#!/usr/bin/env bash # 等 X socket 就绪,避免 Gtk-WARNING: cannot open display 那类抢跑 TIMEOUT=${1:-60} i=0 while [ "$i" -lt "$TIMEOUT" ]; do [ -S /tmp/.X11-unix/X0 ] && exit 0 sleep 1; i=$((i+1)) done exit 0
chmod +x ~/.local/bin/ime-wait-x.sh
以 engine 为例,~/.config/systemd/user/cpis-engine.service:
~/.config/systemd/user/cpis-engine.service
[Unit] Description=Sogou IME NG engine (systemd supervised) After=graphical-session.target Wants=graphical-session.target # 抢名失败时不要熔断,否则单元永久 failed,再也没人拉活 StartLimitIntervalSec=0 [Service] Type=simple ExecStartPre=/bin/bash %h/.local/bin/ime-wait-x.sh 60 ExecStart=/opt/apps/com.cpis/bin/com.cpis.engine.service.start.sh Environment=DISPLAY=:0 Environment=XAUTHORITY=%h/.Xauthority Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus Restart=always RestartSec=3 TimeoutStartSec=90 TimeoutStopSec=15 Nice=10 [Install] WantedBy=graphical-session.target
cpis-panel.service、cpis-hotkey.service 复制一份,把 Description、ExecStart 里的 engine 换成 panel / hotkey 即可。
cpis-panel.service
cpis-hotkey.service
engine
panel
hotkey
此时 D-Bus 激活的三个实例通常已经在跑。如果直接 systemctl --user start,systemd 实例会因为 D-Bus 名字被占用而注册失败退出,接着 Restart=always 进入重启死循环。
systemctl --user start
正确做法是二选一:
systemctl --user daemon-reload systemctl --user enable cpis-engine.service cpis-panel.service cpis-hotkey.service # 重启或注销重登
for n in cpis-engine-service cpis-panel-service cpis-hotkey-service ISE_NODE; do pkill -x "${n:0:15}" 2>/dev/null done systemctl --user daemon-reload systemctl --user enable --now cpis-engine.service cpis-panel.service cpis-hotkey.service
systemctl --user status cpis-engine.service cpis-panel.service cpis-hotkey.service busctl --user list | grep com.cpis # 每个名字只应有一个 owner fcitx5-remote -n # 当前输入法
再故意 kill 一个后端:
pkill -x cpis-engine-ser sleep 5 systemctl --user is-active cpis-engine.service # 应为 active
systemctl --user disable cpis-engine.service cpis-panel.service cpis-hotkey.service rm ~/.config/systemd/user/cpis-{engine,panel,hotkey}.service rm ~/.local/bin/ime-wait-x.sh # 注销重登,交回 D-Bus 激活
上面的 unit 只能处理"进程死了"。还有一种更隐蔽的情况:fcitx5 进程在、D-Bus 名字也在,但主循环被残缺后端阻塞,完全不应答。
可以加一个每分钟探活的 timer,探针用与窗口焦点无关的 D-Bus Introspect:
#!/usr/bin/env bash set -u export XDG_RUNTIME_DIR="/run/user/$(id -u)" export DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/bus" STAMP=/tmp/fcitx5-watchdog.last bad=0 for i in 1 2 3; do if timeout 8 busctl --user --timeout=6 --no-pager call \ org.fcitx.Fcitx5 / org.freedesktop.DBus.Introspectable Introspect >/dev/null 2>&1; then bad=0; break fi bad=$((bad+1)); sleep 5 done [ "$bad" -lt 3 ] && exit 0 now=$(date +%s); last=$(cat "$STAMP" 2>/dev/null || echo 0) [ $((now - last)) -lt 600 ] && exit 0 # 10 分钟冷却,避免恢复风暴 echo "$now" > "$STAMP" systemctl --user restart cpis-engine.service cpis-panel.service cpis-hotkey.service
配套 fcitx5-ime-watchdog.service(Type=oneshot)+ .timer(OnUnitActiveSec=1min)即可。
fcitx5-ime-watchdog.service
Type=oneshot
.timer
OnUnitActiveSec=1min
注意:如果卡死的是 fcitx5 本体而不是 cpis 后端,重启三个后端不一定能救回来,最稳仍是注销重登。
DISPLAY=:0
start.sh
systemctl --user status cpis-*
如果你也遇到"切到搜狗没反应",可以先看两处日志再决定要不要上这套:
tail -50 ~/.cache/fcitx5/fcitx5.log systemctl --user status cpis-engine.service cpis-panel.service cpis-hotkey.service
确实是个不错的方案
我每次都是重启输入法
Featured Collection
Popular Ranking
Popular Events
Deepin 25 搜狗输入法突然打不出字?给 cpis 多进程加 systemd 看门狗
一、现象
用着用着切到搜狗就打不出中文,候选窗不出现,有时过几秒恢复,有时必须重启 fcitx5 甚至注销重登。检查进程会发现:
fcitx5主进程还活着cpis-engine-service/cpis-panel-service/cpis-hotkey-service三个后端已经不见了,或者只剩一个"空壳"二、根因
搜狗 NG 在 fcitx5 里只是一个前端插件,真正的拼词引擎和候选窗是两个独立的 D-Bus 按需激活进程:
这些后端由 D-Bus 激活,没有 systemd Restart。后端异常退出后,前端插件还缓存着失效连接,于是每次按键都失败。
本机
~/.cache/fcitx5/fcitx5.log里的直接证据:另外
/opt/apps/com.cpis/etc/ise.ini里有引擎自检:内存紧张时会更容易触发,所以这问题常常和"内存/swap 快满"一起出现。
三、方案:让 systemd 接管三个后端
思路:开机时由 systemd 先把三个服务拉起来。服务自己拿到 D-Bus 名字后,D-Bus 激活机制发现"名字已有 owner",就不会再产生第二个实例;进程挂了由
Restart=always拉活。1. 等 X socket 的小脚本
~/.local/bin/ime-wait-x.sh:2. 三个 user unit
以 engine 为例,
~/.config/systemd/user/cpis-engine.service:cpis-panel.service、cpis-hotkey.service复制一份,把 Description、ExecStart 里的engine换成panel/hotkey即可。3. 启用(关键:不要在当前会话直接 start)
此时 D-Bus 激活的三个实例通常已经在跑。如果直接
systemctl --user start,systemd 实例会因为 D-Bus 名字被占用而注册失败退出,接着Restart=always进入重启死循环。正确做法是二选一:
4. 验证
再故意 kill 一个后端:
5. 回退
四、补充:进程活着但主循环卡死怎么办
上面的 unit 只能处理"进程死了"。还有一种更隐蔽的情况:fcitx5 进程在、D-Bus 名字也在,但主循环被残缺后端阻塞,完全不应答。
可以加一个每分钟探活的 timer,探针用与窗口焦点无关的 D-Bus Introspect:
配套
fcitx5-ime-watchdog.service(Type=oneshot)+.timer(OnUnitActiveSec=1min)即可。注意:如果卡死的是 fcitx5 本体而不是 cpis 后端,重启三个后端不一定能救回来,最稳仍是注销重登。
五、已知限制
DISPLAY=:0和 X socket 逻辑需要另测。start.sh路径或启动参数,升级后建议systemctl --user status cpis-*看一眼。如果你也遇到"切到搜狗没反应",可以先看两处日志再决定要不要上这套: