背景

某台 Arch Linux KDE Plasma 桌面系统在登录后检查用户级 systemd 服务状态时,发现曾经出现过 Akonadi 相关失败记录。Akonadi 是 KDE PIM 体系中的个人信息管理后端,常被 KMail、Kontact、KOrganizer、KAddressBook、日历提醒、联系人、邮件索引等组件使用。

问题的表面现象比较迷惑:

systemctl --user --failed --no-pager

一开始能看到 Akonadi 相关失败;但随后执行:

akonadictl status

又显示:

Akonadi Control: running
Akonadi Server: running

也就是说,systemd 认为某次 Akonadi 启动失败了,但 Akonadi 本身后来又确实运行起来了。

这类问题如果直接重建 Akonadi 数据库,很容易扩大风险。更合理的处理方式是先确认失败链路,再做最小可回退修复。

初始现象

用户级日志中可以看到类似记录:

Starting Akonadi Control...
akonadiserver: Starting up the Akonadi Server...
akonadi_control.service: start operation timed out. Terminating.
akonadi_control.service: Killing process ... (mysqld) with signal SIGKILL.
akonadi_control.service: Failed with result 'timeout'.
Failed to start Akonadi Control.

Akonadi 使用内置 MariaDB/MySQL 后端。日志中 mysqld 被 systemd 杀掉,说明失败并不是单纯的前端组件问题,而是 Akonadi 启动流程中包含的数据库进程被一并终止了。

系统级 unit 内容类似:

[Service]
ExecStart=/usr/bin/akonadi_control
Type=dbus
BusName=org.freedesktop.Akonadi.Control
TimeoutSec=5sec
Slice=background.slice
Restart=no

最初可疑点是 TimeoutSec=5sec。Akonadi 登录阶段启动时需要拉起 MariaDB、初始化数据库、注册 D-Bus 名称。5 秒确实偏紧。

第一轮修正:把 TimeoutSec 临时改为 30 秒

为了确认是否只是 5 秒太短,使用用户级 systemd drop-in 覆盖配置,而不是修改 /usr/lib/systemd/user/akonadi_control.service 原文件。

执行:

systemctl --user edit akonadi_control.service

写入:

[Service]
TimeoutSec=30sec

然后:

systemctl --user daemon-reload
systemctl --user show akonadi_control.service -p TimeoutStartUSec -p TimeoutStopUSec

确认变为:

TimeoutStartUSec=30s
TimeoutStopUSec=30s

手动 stop/start 测试中,Akonadi 可以正常启动:

akonadictl stop
akonadictl start
akonadictl status

日志显示:

Akonadi server is now operational.
Started Akonadi Control.

这说明 Akonadi 数据库本身不是彻底损坏状态。

重新登录后问题仍然复现

重新登录后,问题再次出现,但时间点变成了 30 秒:

Starting Akonadi Control...
30 秒后 start operation timed out
随后 stop-sigterm timed out
systemd 杀掉 akonadi_control 和 mysqld
Failed with result 'timeout'

这一步非常关键。它说明:

  • 30 秒 override 已经生效;
  • 问题不是简单的“5 秒太短”;
  • 登录阶段第一次启动存在更深层的卡住或竞态。

更奇怪的是,失败后 Akonadi 又运行起来了:

akonadictl status

显示:

Akonadi Control: running
Akonadi Server: running

但:

systemctl --user status akonadi_control.service

却显示:

Active: inactive (dead)

这说明当前运行中的 Akonadi 实例不一定属于 akonadi_control.service 这个 unit 管理。

关键诊断:当前 Akonadi 挂在 kalendarac 的 app slice 下

进一步检查进程、cgroup 和 D-Bus owner:

pgrep -a -f 'akonadi|mysqld.*akonadi'
ps -o pid,ppid,stat,etime,cmd -C akonadi_control -C akonadiserver -C mysqld
busctl --user status org.freedesktop.Akonadi.Control
systemd-cgls --user | grep -A20 -B10 -Ei 'akonadi|mysqld'

结果显示:

  • akonadi_control.service 自身已经 failed 或 inactive;
  • 当前活着的 Akonadi 进程属于 app-org.kde.kalendarac@autostart.service
  • org.freedesktop.Akonadi.Control 当前 D-Bus owner 也指向这个后起实例;
  • kalendarac 是 KDE Calendar Reminders 组件,会在登录时自启动。

由此可以还原真实链路:

KDE 登录
↓
kalendarac 自动启动
↓
kalendarac 过早触发 Akonadi
↓
systemd --user 同时尝试通过 akonadi_control.service 启动 Akonadi
↓
启动路径发生竞态
↓
systemd 管理的那次 akonadi_control.service 超时失败
↓
mysqld 被强杀
↓
随后 Akonadi 又通过 kalendarac 相关路径重新起来
↓
Akonadi 实际可用,但 systemd 留下 failed 记录

这解释了为什么会同时出现:

systemctl 显示 Akonadi failed / inactive
akonadictl 显示 Akonadi running

为什么不重建 Akonadi 数据库

MariaDB 日志中虽然出现过 crash recovery:

Recovering after a crash using tc.log
Crash table recovery finished.
ready for connections.

但这不是数据库已经损坏的证据,而是因为前一次 mysqld 被 systemd SIGKILL 强杀,下一次启动时自然会做恢复。

排查中没有发现:

schema corruption
permission denied
root-owned 文件
socket 权限异常
lock 文件残留导致无法启动
持续崩溃循环

所以没有理由重建:

~/.local/share/akonadi
~/.config/akonadi

直接删除或重建 Akonadi 数据库属于高风险绕路,不是本次问题的根本修复。

最小可回退修复:禁用当前用户的 kalendarac 自启动

既然根因指向 kalendarac 登录早期触发 Akonadi,那么修复方向应当是切断这个过早触发源,而不是继续扩大 timeout。

系统级 autostart 文件位于:

/etc/xdg/autostart/org.kde.kalendarac.desktop

不修改系统级文件,而是在当前用户目录创建 shadow 文件:

~/.config/autostart/org.kde.kalendarac.desktop

内容基于系统级文件复制,并在末尾追加:

Hidden=true

这样只会禁用当前用户的 Calendar Reminders 登录自启动。回退方式也很简单:删除这个用户级 shadow 文件即可。

该修复不会:

卸载 KDE PIM
禁用 Akonadi
删除数据库
修改 /usr/lib
修改 /etc
mask systemd service

它只是让 kalendarac 不再登录时过早启动。

撤销临时 30 秒 override

在禁用 kalendarac 后重新登录,Akonadi 已经可以正常启动。此时可以撤销之前的 30 秒 timeout 临时修正,让 akonadi_control.service 回到系统默认 5 秒。

建议不要直接删除,先改名备份:

mv -v ~/.config/systemd/user/akonadi_control.service.d/override.conf \
~/.config/systemd/user/akonadi_control.service.d/override.conf.disabled-$(date +%Y%m%d-%H%M%S)

然后:

systemctl --user daemon-reload

确认恢复默认:

systemctl --user show akonadi_control.service -p TimeoutStartUSec -p TimeoutStopUSec

预期:

TimeoutStartUSec=5s
TimeoutStopUSec=5s

最终验证

重启或重新登录后执行:

systemctl --user --failed --no-pager

结果:

0 loaded units listed.

查看 Akonadi 日志:

journalctl --user -b -u akonadi_control.service --no-pager -o short-iso | grep -Ei 'Starting|Started|operational|timeout|Failed|Killing'

正常结果类似:

Starting Akonadi Control...
Starting up the Akonadi Server...
Akonadi server is now operational.
Started Akonadi Control.

没有再出现:

start operation timed out
Killing process ... mysqld
Failed to start Akonadi Control
Failed with result 'timeout'

检查进程:

pgrep -a -f 'kalendarac|akonadi|mysqld.*akonadi'

结果中没有 kalendarac,但 Akonadi 可以正常运行:

/usr/bin/akonadi_control
/usr/bin/akonadiserver
/usr/bin/mysqld --defaults-file=...

这说明:

  • kalendarac 自启动禁用生效;
  • Akonadi 不再被登录早期的日历提醒组件制造竞态;
  • akonadi_control.service 使用默认 5 秒 timeout 也能正常启动;
  • systemd 用户级失败列表保持干净。

关于日志中的 portal 警告

Akonadi 启动过程中仍可能出现:

Failed to register with host portal
Could not register app ID

这些属于 KDE/portal 相关警告噪音。只要后续出现:

Akonadi server is now operational.
Started Akonadi Control.

并且没有 timeout、SIGKILL、failed result,就不应把这些 portal 警告当作 Akonadi 启动失败处理。

结论

本次故障的根因不是 Akonadi 数据库损坏,也不是 MariaDB 无法启动,而是 KDE 登录阶段 kalendarac 自动启动过早触发 Akonadi,造成 akonadi_control.service 的 systemd/DBus 启动路径发生竞态。

最终有效修复是:

禁用当前用户的 kalendarac 自启动
保留 Akonadi 正常按需启动
撤销临时 TimeoutSec=30sec override
不重建数据库
不卸载 KDE PIM
不修改系统级 unit

最终系统状态:

systemctl --user --failed → 0 failed units
akonadi_control.service → 正常启动
kalendarac → 当前用户不再登录自启
Akonadi 数据库 → 保持原状
TimeoutSec → 恢复系统默认 5 秒

这类 KDE PIM 问题最容易被误判为“数据库坏了”。实际排查中,应优先区分三件事:

Akonadi 本体是否可启动
systemd unit 是否管理当前实例
登录阶段是否有其他组件过早触发 Akonadi

只有确认存在数据库损坏、权限错误或 schema 错误时,才应考虑重建 Akonadi 数据库。否则,最小可回退修复通常更安全。

Leave a Reply

Your email address will not be published. Required fields are marked *