会议生命周期与状态对账
转人工会议跨越 FreeSWITCH、callflow-esl 和 callout-server。本文说明各层保存什么状态,以及会议成员意外离开后如何收尾。
状态归属
callflow-esl的callflow.conferences、conference_members和conference_events保存会议实体、成员快照与会控事件;会议管理 HTTP 契约见 HTTP 接口。callout-server的callout.conference_sessions关联外呼 attempt、客户通道 UUID、主坐席和 cell。其持久状态为active或ended。会议加锁属于 FreeSWITCH 会控状态,不是该表的会话状态;reconciled是对账事件名,不是会话状态。- FreeSWITCH
mod_conference的实时成员数反映媒体层是否仍有成员。callout-server查询它来补充列表中的liveMemberCount与liveStatus(live、ended或unknown)。
会议事件与写入顺序
常驻 Inbound 的 conference::maintenance 事件由进程级消费者统一处理。Outbound 在常规模式和应急 all 模式都不执行共享状态持久化;会话 Controller 只响应本地通知和媒体副作用。默认同一 FreeSWITCH 只有一个会议持久化消费者,多实例唯一消费租约不在此机制内。
成员入会、离会、静音、禁听、角色和会议生命周期持久化到 PostgreSQL。start-talking、stop-talking、energy-level(含 speaking 别名)只更新内存和本地监听器,Redis 按成员合并最新快照,每秒最多一次;离会、销毁会取消待写定时器。播放与录音事件交给各自状态处理器,不隐式 upsert 成员。成员列表校准仅在持久字段变化时写库。
全部会议成员写入、离会、销毁和主动刷新共用按 conferenceId 串行的进程队列,入队保存快照,失败被记录后后续任务继续,不同会议并行。列表查询期间若收到成员维护事件,丢弃旧列表并保留事件更新,避免把已离会成员重新写回。外部坐席仅同步成员快照;只有真实本地 SessionRunner 才登记控制归属。
Inbound 中断使跨腿等待快速失败,保留本腿控制;尚未就绪时拒绝新增跨腿操作。连接采用带抖动的指数退避恢复,重新订阅后校准跟踪的通道和会议,不重放断线期间的历史事件。
前台业务收尾
callflow-esl 的 callout-flow-business 在转人工节点调用 joinConferenceWithAgentWatchdog。坐席入会前,看门狗按该次路由的振铃超时等待;超时后返回失败,由流程的 timeout 出口或默认出口继续处理。坐席入会与离会优先通过事件通知处理,另有 5 秒低频成员数校准及结束前复核;具体等待和收尾由业务实现(src/business/shared/callout/transfer.ts)决定。
客户或坐席正常挂机时,事件处理路径会更新通话腿和会议会话,并释放坐席占用。需要查看外呼业务如何进入会议,可从 内置业务 进入。
读时状态校准
callout-server 查询会议列表或详情时,会向会议所属 cell 的 FreeSWITCH 查询实时成员数。成员数大于零显示 live;成员数为零显示 ended;无法连接或无法确定 cell 时显示 unknown,保留数据库原状态。
超过 conferenceReconcile.graceMs 的 active 会话若被查出已无成员,列表查询会异步触发修复,详情查询也会触发修复。读时返回的实时状态可先于持久状态更新;修复逻辑见 conference-sessions.ts 与 conference-live-repair.ts。
后台对账
callout-server 的 runConferenceReconcile 定时查询 active 会话,只处理本实例持有监听租约的 cell。当前配置默认 intervalMs = 30000、graceMs = 60000;宽限期避免坐席仍在振铃、会议尚未有成员时被误判为空房。无 cellId 的历史会话归默认 cell;非空但已经从配置移除的 cell 会记录错误事件并跳过。
对超过宽限期的会话,worker 向 FreeSWITCH 查询成员数。查询失败时跳过该会话,不据此结束会议。确认成员数为零后,worker 将尚未结束的坐席通话腿置为完成或失败,释放相应坐席,尝试挂断残留客户通道,关闭会议会话,并记录 conference_session_reconciled 事件。默认值由 apps/callout-server/src/config.ts 提供,worker 实现在 apps/callout-server/src/services/conference/conference-reconcile.ts。
这套收尾只处理 callout-server 管理的转人工会议会话;callflow-esl 的普通会议 HTTP 会控仍以自己的会议记录和 FreeSWITCH 实时状态为准。