ejabberd 18.04版本mod_mam处理离线消息触发报错
先梳理下你的场景:你从源码编译了带MySQL支持的ejabberd 18.04,基础功能都正常,启用mod_mam配置后,发送离线消息时触发了offline_message_hook的function_clause崩溃错误,但奇怪的是消息已经能正常存入archive表,而且旧版本17.01里这个功能是正常的。
这个function_clause错误本质是调用mod_mam的offline_message函数时,传入的参数和函数定义的参数不匹配,结合版本差异,给你几个具体的排查和解决方向:
1. 优先检查MySQL表结构是否适配18.04版本
ejabberd 18.04相对于17.01,mod_mam的数据库表结构可能有字段调整。哪怕消息能存进archive表,部分字段的缺失或类型不匹配,都会导致后续钩子处理逻辑出错。
- 找到你ejabberd源码目录下的
sql/mysql/mod_mam.sql脚本 - 对比你当前MySQL数据库里的
archive、archive_prefs等相关表结构,执行脚本中新增或修改的SQL语句,确保表结构和18.04版本完全匹配
2. 验证源码编译时mod_mam的配置是否完整
因为是源码编译,有可能编译过程中没有正确启用mod_mam的全部功能模块,导致离线消息处理的钩子函数未正确编译:
- 重新编译ejabberd时,明确指定启用mod_mam:
./configure --enable-modules=mod_mam --enable-mysql - 确保编译依赖的第三方库(比如p1-mysql、p1-cache)都已经正确安装,避免编译时缺失部分功能
3. 调整mod_mam的配置参数,补充必要项
试试给mod_mam添加更多配置项,确保离线消息处理的上下文参数正确:
modules: ... mod_mam: db_type: sql default: always assume_mam_usage: true # 新增该参数,确保离线消息处理时的上下文匹配 pm: always # 明确开启私人消息归档 muc: always # 按需开启群组消息归档,不需要可以删掉 ...
4. 开启详细日志定位参数不匹配点
如果上面的方法都没解决,你可以把ejabberd的日志级别调高到5(loglevel: 5),重启后再触发离线消息错误,查看日志里传入mod_mam:offline_message的具体参数结构,对比18.04源码中该函数的定义,就能精准定位参数不匹配的地方。
5. 对比17.01和18.04的mod_mam源码差异
如果愿意折腾,可以对比ejabberd 17.01和18.04版本中mod_mam.erl文件里offline_message函数的定义,看看是否是参数结构发生了变化(比如元组字段增减、参数个数变化),这种情况虽然少见,但源码编译时可能因为自定义配置导致兼容问题。
从你的情况来看,消息已经能存入数据库,说明归档的核心逻辑是正常的,问题大概率出在离线消息钩子的参数适配或者表结构的细节差异上,优先排查前两个方向应该就能解决。
内容的提问来源于stack exchange,提问作者Christian

