Fix A2A messaging DB session handling#681
Conversation
## 问题1:ForeignKeyViolationError(users.identity_id → identities.id) 根因:channel_user_service._create_channel_user() 调用 registration_service.find_or_create_identity(),后者通过 identity_dao.create_identity() 开启独立的 async with self.session()。 由于后台channel handler 直接使用 async_session()(未经 Depends(get_db)), _session_ctx 未设置,DAO 打开新 session 执行 flush 后退出时被 rollback, Identity 行消失,随后 User INSERT 的 FK 引用失效。 修复:_create_channel_user 和 get_platform_user_by_org_member 改为 直接在传入的 db session 上创建 Identity(db.add + flush), 确保 Identity 和 User 在同一事务内,彻底解决 FK 违反。 ## 问题2:LLM调用期间长期占用DB连接 所有channel在调用LLM时仍持有数据库连接(30~180s),耗尽连接池。 修复:所有channel统一采用三段式事务模式: - Phase 1:短事务加载数据、保存用户消息 → commit + close - Phase 2:调用LLM(_call_llm_with_config,无DB session) - Phase 3:新短事务(async_session)保存回复 ## 修复文件清单 - database.py:get_db 正确设置/重置 _session_ctx ContextVar - tenants.py:修复 bind_org_member 调用签名 - enterprise.py:修复 get_email_templates 调用签名 - feishu.py:修复图片处理路径的会话泄漏 - teams.py:修复webhook持有Depends(get_db)连接跨LLM调用 - whatsapp.py:修复LLM调用期间持有连接 - wechat_channel.py:修复LLM调用期间持有连接 - wecom_stream.py:修复LLM调用期间持有连接 - discord_gateway.py:修复LLM调用期间持有连接 - channel_user_service.py:根治Identity FK违反,同session创建Identity+User
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2c76cc8712
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| identity = Identity( | ||
| email=email, | ||
| phone=normalized_phone, | ||
| username=username, |
There was a problem hiding this comment.
Keep channel identity usernames unique
When the generated channel username already belongs to another Identity with a different email/phone (for example a pre-existing web username or the same sanitized channel ID from another provider), this direct insert bypasses registration_service.find_or_create_identity's is_username_taken suffix logic and the db.flush() will hit the unique identities.username constraint, breaking lazy channel user creation. Keep the username de-duplication while still creating the identity in the caller's session.
Useful? React with 👍 / 👎.
| await _send_whatsapp_messages(config, sender_phone, reply_text) | ||
| config.is_connected = True | ||
| db.add(ChatMessage(agent_id=agent_id, user_id=platform_user_id, role="assistant", content=reply_text, conversation_id=session_conv_id)) | ||
| sess.last_message_at = datetime.now(timezone.utc) | ||
| await db.commit() | ||
| async with _async_session() as _save_db: |
There was a problem hiding this comment.
Preserve WhatsApp connection status updates
When WhatsApp delivery succeeds or fails, this path now only sends the message and records the assistant reply; it no longer updates ChannelConfig.is_connected. The previous code set it to True after a successful _send_whatsapp_messages call and False in the exception branch, so the admin/UI connection indicator can remain stale for WhatsApp agents despite the latest delivery result.
Useful? React with 👍 / 👎.
Summary
Tests