ForcePilot/backend/package/yuxi/channels/infrastructure/channel_use_cases.py
Kris 8eead29de0 refactor: 批量清理冗余空行,优化部分枚举使用方式
1.  移除所有适配器文件中多余的空导入行
2.  调整ValidationError继承,移除不必要的ValueError继承
3.  修正多处ChannelType使用方式,从.value改为直接使用枚举实例
4.  优化飞书插件部分硬编码渠道类型为枚举实例
5.  更新wechat_ilink插件清单与适配器配置
6.  新增飞书目录适配器缓存清理支持判断与iLink生命周期适配器凭据轮换支持判断
7.  优化配置处理器历史查询逻辑,区分键不存在与无历史记录场景
2026-07-04 00:14:56 +08:00

1164 lines
56 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""渠道用例服务聚合与请求级 factory。
本模块是编排层的用例装配点,负责将请求级被驱动适配器、
应用级单例(注册中心等)与领域服务装配为 ``ChannelUseCases`` 聚合
(含 6 个用例服务实例与 19 个类型化领域端口绑定),对齐
external_systems 的 ``UseCases`` + ``create_use_cases_from_db(db)`` 模式。
装配顺序:
1. ``create_driven_adapters(db)`` 创建被驱动适配器聚合
2. 从 DI 容器获取应用级单例(注册中心等)
3. 按依赖图拓扑顺序构造领域服务
4. 通过 ``Pipeline.create()`` 创建管道
5. 实例化用例服务并注入依赖
"""
# ruff: noqa: I001
# 本文件为组合根200+ 行导入按装配语义分组(管道/用例/DTO/适配器/注册表/领域服务/DI
# 与 isort 的字母序合并规则冲突,故豁免 I001 以保留可读性。
from __future__ import annotations
from collections.abc import Iterable
from dataclasses import dataclass
from typing import Any
from arq import ArqRedis
from redis.asyncio import Redis
from sqlalchemy.ext.asyncio import AsyncSession
from yuxi.channels.adapters import DrivenAdapters, create_driven_adapters
from yuxi.channels.adapters.default_content_moderation_adapter import (
DefaultContentModerationAdapter,
)
from yuxi.channels.adapters.inmemory_realtime_metrics_adapter import (
InmemoryRealtimeMetricsAdapter,
)
from yuxi.channels.adapters.report_repository_adapter import (
SqlAlchemyReportRepositoryAdapter,
)
from yuxi.channels.application.circuit_breaker.channel_circuit_breaker import (
ChannelCircuitBreaker,
)
from yuxi.channels.application.executor.channel_tool_executor import ChannelToolExecutor
from yuxi.channels.application.executor.message_operation_executor import (
MessageOperationExecutor,
)
from yuxi.channels.application.health.channel_probe import ChannelProbe
from yuxi.channels.application.health.health_aggregator import HealthAggregator
from yuxi.channels.application.lifecycle.plugin_lifecycle_manager import (
PluginLifecycleManager,
)
from yuxi.channels.application.lifecycle.plugin_loader import PluginLoader
from yuxi.channels.application.pipeline.control_plane.audit_context_builder import (
AuditContextBuilder,
)
from yuxi.channels.application.pipeline.control_plane.control_plane_pipeline import (
ControlPlanePipeline,
)
# 管道
from yuxi.channels.application.pipeline.inbound.inbound_pipeline import InboundPipeline
from yuxi.channels.application.pipeline.outbound.outbound_pipeline import (
OutboundPipeline,
)
# framework 层应用级单例(健康聚合器、插件生命周期管理器)
from yuxi.channels.application.executor.pre_tool_call_trusted_injector import (
PreToolCallTrustedInjector,
)
# 用例服务实现(唯一允许 import 用例实现类的地方)
from yuxi.channels.application.usecase.admin_message_service import AdminMessageService
from yuxi.channels.application.usecase.channel_control_service import (
ChannelControlService,
)
from yuxi.channels.application.usecase.content_review_query_service import (
ContentReviewQueryService,
)
from yuxi.channels.application.usecase.health_check_service import HealthCheckService
from yuxi.channels.application.usecase.inbound_message_service import (
InboundMessageService,
)
from yuxi.channels.application.usecase.plugin_lifecycle_service import (
PluginLifecycleService,
)
# DTO
from yuxi.channels.contract.dtos.channel import ChannelType
from yuxi.channels.contract.dtos.outbox import OutboxConfig, OutboxConfigHolder
# 错误类型装配期冲突校验INV-7 错误显式化)
from yuxi.channels.contract.errors import RuleViolationError
# 适配器协议(管道注册表键类型)
from yuxi.channels.contract.plugin.adapters.attachment_upload_adapter import (
AttachmentUploadAdapter,
)
from yuxi.channels.contract.plugin.adapters.command_adapter import CommandAdapter
from yuxi.channels.contract.plugin.adapters.content_moderation_adapter import (
ContentModerationAdapter,
)
from yuxi.channels.contract.plugin.adapters.directory_adapter import DirectoryAdapter
from yuxi.channels.contract.plugin.adapters.doctor_adapter import DoctorAdapter
from yuxi.channels.contract.plugin.adapters.inbound_adapter import InboundAdapter
from yuxi.channels.contract.plugin.adapters.lifecycle_adapter import (
LifecycleAdapter,
)
from yuxi.channels.contract.plugin.adapters.login_adapter import LoginAdapter
from yuxi.channels.contract.plugin.adapters.mention_adapter import MentionAdapter
from yuxi.channels.contract.plugin.adapters.message_ops_adapter import MessageOpsAdapter
from yuxi.channels.contract.plugin.adapters.outbound_adapter import OutboundAdapter
from yuxi.channels.contract.plugin.adapters.rich_message_adapter import RichMessageAdapter
from yuxi.channels.contract.plugin.adapters.session_adapter import SessionAdapter
from yuxi.channels.contract.plugin.adapters.status_adapter import StatusAdapter
from yuxi.channels.contract.plugin.adapters.streaming_adapter import (
StreamingAdapter,
)
from yuxi.channels.contract.plugin.adapters.tools_adapter import ToolsAdapter
from yuxi.channels.contract.plugin.adapters.webhook_test_adapter import WebhookTestAdapter
from yuxi.channels.contract.plugin.adapters.whitelist_adapter import WhitelistAdapter
from yuxi.channels.contract.plugin.adapters.wizard_adapter import WizardAdapter
from yuxi.channels.adapters import MessageOpsPortAdapter
# 适配器类型(管道注册表值类型)
from yuxi.channels.contract.ports.driven.agent_run_execution_port import (
AgentRunExecutionPort,
)
from yuxi.channels.contract.ports.driven.channel_context_provider_port import (
ChannelContextProviderPort,
)
from yuxi.channels.contract.ports.driven.channel_session_repository_port import (
ChannelSessionRepositoryPort,
)
from yuxi.channels.contract.ports.driven.channel_tool_executor_port import (
ChannelToolExecutorPort,
)
from yuxi.channels.contract.ports.driven.content_review_repository_port import (
ContentReviewRepositoryPort,
)
# EventPublisherPort应用层通过此端口契约依赖事件发布能力组合根绑定到 EventBus
from yuxi.channels.contract.ports.driven.event_publisher_port import EventPublisherPort
from yuxi.channels.contract.ports.driven.outbox_repository_port import (
OutboxRepositoryPort,
)
from yuxi.channels.contract.ports.driven.pairing_repository_port import (
PairingRepositoryPort,
)
from yuxi.channels.contract.ports.driven.queue_port import QueuePort
from yuxi.channels.contract.ports.driven.report_repository_port import (
ReportRepositoryPort,
)
from yuxi.channels.contract.ports.driving.account_management_port import (
AccountManagementPort,
)
from yuxi.channels.contract.ports.driving.admin_message_port import AdminMessagePort
from yuxi.channels.contract.ports.driving.analytics_view_port import (
AnalyticsViewPort,
)
from yuxi.channels.contract.ports.driving.audit_query_port import AuditQueryPort
from yuxi.channels.contract.ports.driving.capability_query_port import (
CapabilityQueryPort,
)
from yuxi.channels.contract.ports.driving.channel_login_port import (
ChannelLoginPort,
)
from yuxi.channels.contract.ports.driving.config_management_port import (
ConfigManagementPort,
)
from yuxi.channels.contract.ports.driving.content_review_port import ContentReviewPort
from yuxi.channels.contract.ports.driving.content_review_query_port import (
ContentReviewQueryPort,
)
from yuxi.channels.contract.ports.driving.dashboard_view_port import (
DashboardViewPort,
)
from yuxi.channels.contract.ports.driving.directory_port import DirectoryPort
from yuxi.channels.contract.ports.driving.doctor_port import DoctorPort
from yuxi.channels.contract.ports.driving.health_check_port import HealthCheckPort
from yuxi.channels.contract.ports.driving.inbound_message_port import (
InboundMessagePort,
)
from yuxi.channels.contract.ports.driving.message_management_port import (
MessageManagementPort,
)
from yuxi.channels.contract.ports.driving.outbox_management_port import (
OutboxManagementPort,
)
from yuxi.channels.contract.ports.driving.pairing_management_port import (
PairingManagementPort,
)
from yuxi.channels.contract.ports.driving.plugin_lifecycle_port import (
PluginLifecyclePort,
)
from yuxi.channels.contract.ports.driving.plugin_management_port import (
PluginManagementPort,
)
from yuxi.channels.contract.ports.driving.report_management_port import (
ReportManagementPort,
)
from yuxi.channels.contract.ports.driving.session_management_port import (
SessionManagementPort,
)
from yuxi.channels.contract.ports.driving.user_binding_port import (
UserBindingPort,
)
from yuxi.channels.contract.ports.driving.whitelist_management_port import (
WhitelistManagementPort,
)
from yuxi.channels.contract.ports.driving.wizard_port import WizardPort
# 注册表(应用级单例)
from yuxi.channels.core.registry.capability_registry import CapabilityRegistry
from yuxi.channels.core.registry.command_registry import CommandRegistryTable
from yuxi.channels.core.registry.identity_resolver_registry import (
IdentityResolverRegistry,
)
from yuxi.channels.core.registry.plugin_registry import PluginRegistry
from yuxi.channels.core.registry.route_match_registry import RouteMatchRegistry
from yuxi.channels.core.registry.whitelist_registry import WhitelistRegistry
# 领域服务
from yuxi.channels.core.service.account_lifecycle_service import (
AccountLifecycleService,
)
from yuxi.channels.core.service.ack_decision_maker import AckDecisionMaker
from yuxi.channels.core.service.bot_loop_budget_guard import BotLoopBudgetGuard
from yuxi.channels.core.service.capability_verifier import CapabilityVerifier
from yuxi.channels.core.service.command_registry import CommandRegistry
from yuxi.channels.core.service.common_command_adapter import CommonCommandAdapter
from yuxi.channels.core.service.config_manager import ConfigManager
from yuxi.channels.core.service.credential_service import CredentialService
from yuxi.channels.core.service.degradation_manager import DegradationManager
from yuxi.channels.core.service.dm_security_guard import DmSecurityGuard
from yuxi.channels.core.service.doctor_service import DoctorService
from yuxi.channels.core.service.fence_guard import FenceGuard
from yuxi.channels.core.service.identity_resolver import IdentityResolver
from yuxi.channels.core.service.mention_evaluator import MentionEvaluator
from yuxi.channels.core.service.qr_login_service import QrLoginService
from yuxi.channels.core.service.route_resolver import RouteResolver
from yuxi.channels.core.service.session_merger import SessionMerger
from yuxi.channels.core.service.status_writeback_handler import StatusWritebackHandler
from yuxi.channels.core.service.truncation_detector import TruncationDetector
from yuxi.channels.core.service.trusted_message_guard import TrustedMessageGuard
from yuxi.channels.core.service.wizard_service import WizardService
# DI 容器
from yuxi.channels.infrastructure.dependency_injection import (
DependencyInjectionContainer,
)
# 全局配置(组合根读取配置源,构造 OutboxConfig 注入应用层§6.1
from yuxi.config.app import config as app_config
# 调度器worker 进程装配与一次性报告任务调度)
from yuxi.scheduler.infrastructure.container import create_scheduler_service
__all__ = [
"ChannelUseCases",
"create_channel_use_cases",
]
@dataclass
class ChannelUseCases:
"""渠道用例服务聚合。
串联 ``create_driven_adapters(db)`` → 领域服务 → 管道 → 用例服务。
请求级创建,共享同一 ``db`` session。
对齐 external_systems 的 ``UseCases`` dataclass 模式。字段类型使用驱动
端口 Protocol非实现类保证调用方只依赖端口。
字段:
inbound_message: 入站消息用例(实现 InboundMessagePort
admin_message: 管理员消息用例(实现 AdminMessagePort
plugin_lifecycle: 插件生命周期用例(实现 PluginLifecyclePort
health_check: 健康检查用例(实现 HealthCheckPort
channel_tool_executor: 渠道工具执行器(实现 ChannelToolExecutorPort
由 Agent 后端通过依赖注入显式获取,调用 ``executeChannelTool``
路由到对应插件的 ``executeTool``FR-11
wizard: 安装向导用例(实现 WizardPort覆盖向导步骤查询 / 校验 /
应用 / 完成与 OAuth 回调FR-16
doctor: 配置诊断用例(实现 DoctorPort覆盖诊断检查项查询 / 全量
与单项检查 / 自动修复FR-17
whitelist_management: 白名单管理用例(实现 WhitelistManagementPort
覆盖白名单查询 / 添加 / 移除FR-18
directory: 目录查询用例(实现 DirectoryPort覆盖用户与群组
搜索 / 资料与成员查询FR-14
pairing_management: 配对审批管理用例(实现 PairingManagementPort
覆盖配对记录查询 / 批准 / 拒绝 / 撤销FR-33
config_management: 配置热更新管理用例(实现 ConfigManagementPort
覆盖配置查询 / 更新 / 回滚 / 版本历史FR-37
session_management: 会话管理用例(实现 SessionManagementPort覆盖
会话合并、所有者转移、关闭与统计FR-07 / FR-26
user_binding: 用户绑定用例(实现 UserBindingPort覆盖渠道会话
统一身份的绑定 / 解绑 / 状态查询P3 渐进式绑定,不走控制面管道)。
audit_query: 审计查询用例(实现 AuditQueryPort覆盖审计日志查询
FR-34
account_management: 账户生命周期管理用例(实现 AccountManagementPort
覆盖账户创建 / 更新 / 删除 / 启用 / 禁用 / 查询 / 列表AL-01~AL-04
login: 扫码登录用例(实现 ChannelLoginPort覆盖二维码生成 / 状态
轮询 / 登录确认回调 / 登录态查询QR-03~QR-05 + 运维排查)。
message_management: 消息管理用例(实现 MessageManagementPort覆盖
会话消息查询、全文搜索、状态查询与消息运维操作(撤回 / 重发 /
附件上传,运维排查 / 审计用例)。
plugin_management: 插件生命周期管理用例(实现 PluginManagementPort
覆盖插件加载 / 启动 / 暂停 / 恢复 / 停止 / 卸载 / 重载FR-32
通过控制面管道统一执行认证 / 权限 / 限流 / 分派 / 审计五阶段。
outbox_management: 发件箱管理用例(实现 OutboxManagementPort覆盖
outbox 条目查询 / 统计 / 重投 / 死信管理与重试策略查询OBX-01~OBX-08
capability_query: 能力查询用例(实现 CapabilityQueryPort覆盖渠道
能力列表与单渠道能力详情查询CAP-01 / CAP-02绑定到
``ChannelControlService`` 同一实例(第 15 个类型化端口),聚合
PluginRegistry 中插件的 manifest.capabilities 声明。
content_review: 内容审核用例(实现 ContentReviewPort覆盖管理员
主动触发的 dry-run 预审核CR-01绑定到 ``ChannelControlService``
同一实例(第 16 个类型化端口),经控制面管道执行
``content_review/preview`` 操作。
content_review_query: 内容审核历史查询用例(实现 ContentReviewQueryPort
覆盖审核历史列表与详情查询CR-02 / CR-03由独立的
``ContentReviewQueryService`` 实现,不经控制面管道(数据面语义)。
dashboard_view: 聚合视图用例(实现 DashboardViewPort覆盖全局总览 /
账户总览 / 消息总览 / 会话总览 / 投递总览 / 实时监控指标查询
DSB-01~DSB-04 / DSB-DELIVERY / DSB-REALTIME绑定到
``ChannelControlService`` 同一实例(第 17 个类型化端口),跨子域
KPI 聚合,只读无副作用。
report_management: 报告管理用例(实现 ReportManagementPort覆盖
一次性报告创建 / 查询 / 列表 / 下载RPT-05 / RPT-06 /
RPT-ONEOFF-01 / RPT-ONEOFF-02绑定到 ``ChannelControlService``
同一实例(第 18 个类型化端口)。
analytics_view: 分析视图用例(实现 AnalyticsViewPort覆盖消息深度
分析 / 消息类型分布 / 会话分析 / 投递链路分析 / 投递延迟分布 /
投递漏斗分析ANL-01 / ANL-02 / ANL-04 ~ ANL-07绑定到
``ChannelControlService`` 同一实例(第 19 个类型化端口),经控制
面管道五阶段处理。
"""
inbound_message: InboundMessagePort
admin_message: AdminMessagePort
plugin_lifecycle: PluginLifecyclePort
health_check: HealthCheckPort
channel_tool_executor: ChannelToolExecutorPort
# 控制面健康子集端口ChannelControlService 实现 HealthCheckPort 的
# getSingleHealth / probeChannelDeep 控制面方法,组合根将同一实例
# 绑定到此字段,与数据面 health_check 字段分离以避免模板混淆)。
health_check_control: HealthCheckPort
# 类型化领域端口ChannelControlService 同时实现这些端口,组合根将同一
# 实例绑定到各字段,调用方按窄端口依赖)
wizard: WizardPort
doctor: DoctorPort
whitelist_management: WhitelistManagementPort
directory: DirectoryPort
pairing_management: PairingManagementPort
config_management: ConfigManagementPort
session_management: SessionManagementPort
user_binding: UserBindingPort
audit_query: AuditQueryPort
account_management: AccountManagementPort
login: ChannelLoginPort
message_management: MessageManagementPort
plugin_management: PluginManagementPort
outbox_management: OutboxManagementPort
capability_query: CapabilityQueryPort
content_review: ContentReviewPort
content_review_query: ContentReviewQueryPort
dashboard_view: DashboardViewPort
report_management: ReportManagementPort
analytics_view: AnalyticsViewPort
def _fill_adapter_registry[T](
registry: dict[ChannelType, T],
adapters: Iterable[T],
channel_type: ChannelType,
*,
duplicate_rule: str | None = None,
) -> None:
"""将插件适配器收集到注册表,最后注册者覆盖。
每类适配器每个 ChannelType 仅允许一个实例。``duplicate_rule`` 设置时,
重复注册抛 ``RuleViolationError``INV-7 错误显式化,不静默兜底)。
Args:
registry: 目标注册表(按 ChannelType 索引)。
adapters: 插件注册的适配器列表。
channel_type: 当前渠道类型。
duplicate_rule: 若设置重复注册时抛错rule 为
``{duplicate_rule}:{channel_type}``。
"""
for adapter in adapters:
if duplicate_rule is not None and channel_type in registry:
raise RuleViolationError(
rule=f"{duplicate_rule}:{channel_type}",
)
registry[channel_type] = adapter
def create_channel_use_cases(
db: AsyncSession,
di_container: DependencyInjectionContainer,
) -> ChannelUseCases:
"""请求级 factory创建用例服务聚合。
装配顺序(对齐 external_systems 的 ``create_use_cases_from_db`` 模式):
1. ``create_driven_adapters(db)`` 创建被驱动适配器聚合
2. 从 DI 容器获取应用级单例(注册中心等)
3. 创建领域服务(按依赖图拓扑顺序)
4. 通过 ``Pipeline.create()`` 创建管道
5. 实例化用例服务并注入依赖
Args:
db: SQLAlchemy 异步会话(请求级),被驱动适配器共享此会话。
di_container: 依赖注入容器,提供应用级单例。
Returns:
装配完成的 ``ChannelUseCases`` 实例6 个独立用例服务实例 +
19 个类型化领域端口绑定,详见 ``ChannelUseCases`` 字段文档)。
"""
# 组合根从配置源构造 OutboxConfig 注入应用层,消除应用层对 yuxi.config.app
# 的直接依赖§6.1 应用服务层禁止依赖具体技术适配器)。
# 同时构造 OutboxConfigHolder 支持 updateRetryPolicy 热更新S2 修复):
# holder 在本次请求范围内共享给 OutboxHandler使 updateRetryPolicy 的
# 内存更新对 retry_policy 查询立即生效ConfigPort 持久化保证跨请求最终
# 一致性。
outbox_config = OutboxConfig(
ttl_seconds=app_config.channel_outbox_ttl_seconds,
retry_backoff_schedule=tuple(app_config.channel_outbox_retry_backoff_schedule),
max_retry=app_config.channel_outbox_max_retry,
)
outbox_config_holder = OutboxConfigHolder(outbox_config)
# 1. 被驱动适配器(请求级,共享 db
# Redis 客户端、ARQ 连接池、AgentRunExecutionPort 从 DI 容器解析
# (由 create_host_bootstrap 注册为单例),注入到对应适配器构造函数
# 构造注入INV-5 / ADP-001 / ADP-005 / ADP-022
# EventPublisherPort 同样从 DI 容器解析,注入到 ConfigManager 用于
# 配置变更后发布领域事件CON-030 / ADP-029事件由应用层发布
redis_client: Redis = di_container.resolve(Redis)
arq_pool: ArqRedis = di_container.resolve(ArqRedis)
execution_port: AgentRunExecutionPort = di_container.resolve(AgentRunExecutionPort)
event_publisher: EventPublisherPort = di_container.resolve(EventPublisherPort)
queue_port: QueuePort = di_container.resolve(QueuePort)
adapters: DrivenAdapters = create_driven_adapters(
db,
outbox_config=outbox_config,
redis_client=redis_client,
arq_pool=arq_pool,
execution_port=execution_port,
)
# 2. 应用级单例(从 DI 容器获取)
plugin_registry: PluginRegistry = di_container.resolve(PluginRegistry)
capability_registry: CapabilityRegistry = di_container.resolve(CapabilityRegistry)
command_registry_table: CommandRegistryTable = di_container.resolve(CommandRegistryTable)
identity_resolver_registry: IdentityResolverRegistry = di_container.resolve(IdentityResolverRegistry)
route_match_registry: RouteMatchRegistry = di_container.resolve(RouteMatchRegistry)
whitelist_registry: WhitelistRegistry = di_container.resolve(WhitelistRegistry)
plugin_lifecycle_manager: PluginLifecycleManager = di_container.resolve(PluginLifecycleManager)
health_aggregator: HealthAggregator = di_container.resolve(HealthAggregator)
channel_circuit_breaker: ChannelCircuitBreaker = di_container.resolve(ChannelCircuitBreaker)
# 内容审核域应用级单例(由 create_host_bootstrap 注册到 DI 容器):
# - DefaultContentModerationAdapter未注册插件渠道时的兜底审核适配器
# 注入 DispatchStage 供 content_review/preview 选择适配器。
# - ContentReviewRepositoryPort审核历史仓储端口绑定注入 DispatchStage
# (写路径)与 ContentReviewQueryService读路径
default_moderation_adapter: DefaultContentModerationAdapter = di_container.resolve(DefaultContentModerationAdapter)
review_repository: ContentReviewRepositoryPort = di_container.resolve(ContentReviewRepositoryPort)
# PluginLoader 应用级单例P1 PLG-INSTALL/UNINSTALL 文件操作),由
# create_host_bootstrap 注册到 DI 容器,注入 DispatchStage。
plugin_loader: PluginLoader = di_container.resolve(PluginLoader)
# 3. 领域服务(按依赖图拓扑顺序构造)
# 3.1 纯函数服务(无端口依赖)
mention_evaluator = MentionEvaluator()
truncation_detector = TruncationDetector()
# 3.2 单端口服务
fence_guard = FenceGuard(
cache_port=adapters.cache,
config_port=adapters.config,
logger=adapters.logger,
)
trusted_message_guard = TrustedMessageGuard(
conversation_port=adapters.conversation,
logger=adapters.logger,
)
config_manager = ConfigManager(
config_port=adapters.config,
event_publisher=event_publisher,
logger=adapters.logger,
)
ack_decision_maker = AckDecisionMaker(
config_port=adapters.config,
cache_port=adapters.cache,
logger=adapters.logger,
)
# 3.3 端口 + 注册中心
capability_verifier = CapabilityVerifier(
cache_port=adapters.cache,
registry=capability_registry,
logger=adapters.logger,
)
degradation_manager = DegradationManager(
cache_port=adapters.cache,
plugin_registry=plugin_registry,
logger=adapters.logger,
)
# 通用命令与内置身份解析器由 bootstrap 一次性注册到应用级单例注册表
# (见 ``create_host_bootstrap``),此处仅构造领域服务封装。
command_registry = CommandRegistry(registry=command_registry_table)
route_resolver = RouteResolver(
registry=route_match_registry,
config_port=adapters.config,
cache_port=adapters.cache,
logger=adapters.logger,
)
# 3.4 嵌套依赖关键BotLoopBudgetGuard 必须先于 DmSecurityGuard 构造)
bot_loop_budget_guard = BotLoopBudgetGuard(
cache_port=adapters.cache,
config_port=adapters.config,
logger=adapters.logger,
)
dm_security_guard = DmSecurityGuard(
persistence_port=adapters.persistence,
whitelist_registry=whitelist_registry,
bot_loop_guard=bot_loop_budget_guard,
logger=adapters.logger,
)
identity_resolver = IdentityResolver(
registry=identity_resolver_registry,
config_port=adapters.config,
cache_port=adapters.cache,
logger=adapters.logger,
)
session_merger = SessionMerger(
conversation_port=adapters.conversation,
persistence_port=adapters.persistence,
logger=adapters.logger,
)
# 状态回写处理器FR-09协调 ConversationPort 与 PersistencePort
# 完成渠道侧状态事件回写,含"已发未确认"推进与持久化记录反查。
status_writeback_handler = StatusWritebackHandler(
conversation_port=adapters.conversation,
persistence_port=adapters.persistence,
logger=adapters.logger,
)
# 4. 管道(请求级,注入适配器与领域服务)
# 4.1 适配器注册表(从 PluginRegistry 读取插件注册的适配器填充)
# 约束:每类适配器每个 ChannelType 仅允许一个实例(最后注册者覆盖)。
# 插件注册时由 PluginRegistry 保证唯一性,此处取最后值填充注册表。
status_adapter_registry: dict[ChannelType, StatusAdapter] = {}
session_adapter_registry: dict[ChannelType, SessionAdapter] = {}
inbound_adapter_registry: dict[ChannelType, InboundAdapter] = {}
mention_adapter_registry: dict[ChannelType, MentionAdapter] = {}
streaming_adapter_registry: dict[ChannelType, StreamingAdapter] = {}
outbound_adapter_registry: dict[ChannelType, OutboundAdapter] = {}
rich_message_adapter_registry: dict[ChannelType, RichMessageAdapter] = {}
channel_context_provider_registry: dict[ChannelType, ChannelContextProviderPort] = {}
command_adapter_registry: dict[ChannelType, CommandAdapter] = {}
tools_adapter_registry: dict[ChannelType, ToolsAdapter] = {}
message_ops_adapter_registry: dict[ChannelType, MessageOpsAdapter] = {}
directory_adapter_registry: dict[ChannelType, DirectoryAdapter] = {}
wizard_adapter_registry: dict[ChannelType, WizardAdapter] = {}
doctor_adapter_registry: dict[ChannelType, DoctorAdapter] = {}
whitelist_adapter_registry: dict[ChannelType, WhitelistAdapter] = {}
lifecycle_adapter_registry: dict[ChannelType, LifecycleAdapter] = {}
login_adapter_registry: dict[ChannelType, LoginAdapter] = {}
content_moderation_adapter_registry: dict[ChannelType, ContentModerationAdapter] = {}
webhook_test_adapter_registry: dict[ChannelType, WebhookTestAdapter] = {}
attachment_upload_adapter_registry: dict[ChannelType, AttachmentUploadAdapter] = {}
for channel_type, plugin_da in plugin_registry.listPluginAdapters():
_fill_adapter_registry(status_adapter_registry, plugin_da.status_adapters, channel_type)
_fill_adapter_registry(session_adapter_registry, plugin_da.session_adapters, channel_type)
_fill_adapter_registry(inbound_adapter_registry, plugin_da.inbound_adapters, channel_type)
_fill_adapter_registry(mention_adapter_registry, plugin_da.mention_adapters, channel_type)
_fill_adapter_registry(streaming_adapter_registry, plugin_da.streaming_adapters, channel_type)
_fill_adapter_registry(outbound_adapter_registry, plugin_da.outbound_adapters, channel_type)
_fill_adapter_registry(rich_message_adapter_registry, plugin_da.rich_message_adapters, channel_type)
_fill_adapter_registry(channel_context_provider_registry, plugin_da.channel_context_providers, channel_type)
_fill_adapter_registry(command_adapter_registry, plugin_da.command_adapters, channel_type)
_fill_adapter_registry(tools_adapter_registry, plugin_da.tools_adapters, channel_type)
_fill_adapter_registry(message_ops_adapter_registry, plugin_da.message_ops_adapters, channel_type)
_fill_adapter_registry(directory_adapter_registry, plugin_da.directory_adapters, channel_type)
_fill_adapter_registry(wizard_adapter_registry, plugin_da.wizard_adapters, channel_type)
_fill_adapter_registry(doctor_adapter_registry, plugin_da.doctor_adapters, channel_type)
_fill_adapter_registry(whitelist_adapter_registry, plugin_da.whitelist_adapters, channel_type)
_fill_adapter_registry(lifecycle_adapter_registry, plugin_da.lifecycle_adapters, channel_type)
_fill_adapter_registry(login_adapter_registry, plugin_da.login_adapters, channel_type)
_fill_adapter_registry(
content_moderation_adapter_registry,
plugin_da.content_moderation_adapters,
channel_type,
duplicate_rule="content_moderation_adapter_duplicate",
)
_fill_adapter_registry(webhook_test_adapter_registry, plugin_da.webhook_test_adapters, channel_type)
_fill_adapter_registry(attachment_upload_adapter_registry, plugin_da.attachment_upload_adapters, channel_type)
# 4.2 通用命令适配器内置跨渠道可用FR-15
# whitelist_command_port 延迟回填ChannelControlService 同时实现
# WhitelistManagementPort 与 WhitelistCommandPort在 ControlPlanePipeline
# 之后构造。此处先注入 logger待 ChannelControlService 构造后通过
# setWhitelistCommandPort 回填(与 ChannelToolExecutor.setMessageOperationExecutor
# 同模式)。
common_command_adapter = CommonCommandAdapter(logger=adapters.logger)
# 实时指标采集器(单例,数据面管道采集 + 控制面 dashboard 查询共享)
realtime_metrics = InmemoryRealtimeMetricsAdapter()
# 4.3 入站管道
# 服务账号端口单例:由 create_driven_adapters 创建,共享注入到入站管道
# ServiceAccountResolveStage、控制面管道 AccountHandler 与 AgentRunAdapter。
service_account_port = adapters.service_account
# Agent 渠道访问配置端口单例:共享注入到入站管道 agent-run-enqueue 阶段
agent_access_config_port = adapters.agent_access_config
inbound_pipeline = InboundPipeline.create(
status_adapter_registry=status_adapter_registry,
session_adapter_registry=session_adapter_registry,
inbound_adapter_registry=inbound_adapter_registry,
mention_adapter_registry=mention_adapter_registry,
dm_security_guard=dm_security_guard,
bot_loop_budget_guard=bot_loop_budget_guard,
mention_evaluator=mention_evaluator,
command_registry=command_registry,
identity_resolver=identity_resolver,
route_resolver=route_resolver,
ack_decision_maker=ack_decision_maker,
fence_guard=fence_guard,
plugin_registry=plugin_registry,
config_port=adapters.config,
persistence_port=adapters.persistence,
conversation_port=adapters.conversation,
cache_port=adapters.cache,
agent_run_port=adapters.agent_run,
service_account_port=service_account_port,
agent_access_config_port=agent_access_config_port,
command_adapter_registry=command_adapter_registry,
common_command_adapter=common_command_adapter,
status_writeback_handler=status_writeback_handler,
channel_context_provider_registry=channel_context_provider_registry,
tools_adapter_registry=tools_adapter_registry,
message_ops_adapter_registry=message_ops_adapter_registry,
realtime_metrics=realtime_metrics,
logger=adapters.logger,
)
# 4.4 构造渠道工具执行器,作为 ``ChannelUseCases.channel_tool_executor``
# 字段返回,供 Agent 后端(``resolve_configured_runtime_tools``)通过
# 依赖注入显式获取并调用插件 executeToolFR-11。执行器持有
# tools_adapter_registry按渠道类型路由到对应插件方法。同时注入
# MessageOperationExecutor 用于路由 ``渠道操作_`` 前缀工具调用FR-12
# 由于 MessageOperationExecutor 依赖 message_ops_adapter_registry 与
# PreToolCallTrustedInjector依赖 trusted_message_guard需在
# 执行器构造后通过 setMessageOperationExecutor 回填引用,避免循环依赖。
# 不再通过模块级全局状态注册,符合 INV-3契约显式化与 §9.1
# (不得隐式全局注入)。
channel_tool_executor = ChannelToolExecutor(tools_adapter_registry)
pre_tool_call_trusted_injector = PreToolCallTrustedInjector(
trusted_message_guard=trusted_message_guard,
logger=adapters.logger,
)
message_operation_executor = MessageOperationExecutor(
message_ops_adapter_registry=message_ops_adapter_registry,
pre_tool_call_trusted_injector=pre_tool_call_trusted_injector,
conversation_port=adapters.conversation,
logger=adapters.logger,
)
channel_tool_executor.setMessageOperationExecutor(message_operation_executor)
# 4.5 出站管道
outbound_pipeline = OutboundPipeline.create(
agent_run_port=adapters.agent_run,
fence_guard=fence_guard,
conversation_port=adapters.conversation,
capability_verifier=capability_verifier,
plugin_registry=plugin_registry,
trusted_message_guard=trusted_message_guard,
streaming_adapter_registry=streaming_adapter_registry,
rich_message_adapter_registry=rich_message_adapter_registry,
truncation_detector=truncation_detector,
persistence_port=adapters.persistence,
outbound_adapter_registry=outbound_adapter_registry,
bot_loop_budget_guard=bot_loop_budget_guard,
transaction_port=adapters.transaction,
config_port=adapters.config,
whitelist_registry=whitelist_registry,
event_publisher=event_publisher,
outbox_config=outbox_config,
realtime_metrics=realtime_metrics,
logger=adapters.logger,
)
# 4.6 AdminMessageService 需先于 ControlPlanePipeline 构造
# ControlPlanePipeline 的 dispatch 阶段依赖 AdminMessagePort
# 非控制面管道路径限流cache_port与审计audit_log_repo由用例
# 服务自行实现,不依赖 ControlPlanePipeline 的 RateLimitStage / AuditStage。
admin_message_service = AdminMessageService(
outbound_pipeline=outbound_pipeline,
idempotency_repo=adapters.persistence,
session_repo=adapters.persistence,
audit_log_repo=adapters.persistence,
cache_port=adapters.cache,
logger=adapters.logger,
config_port=adapters.config,
plugin_registry=plugin_registry,
)
# 4.7.1 扫码登录领域服务QR-03~QR-05
# 协调 LoginAdapter编排二维码生成 / 状态轮询 / 登录确认回调。
# 登录态持久化到 ConfigPort 的 ACCOUNT 作用域key=login_status
# 由 CredentialService 通过 setLoginStatus 写入。
# 注入到 ControlPlanePipeline 的 login_service 阶段。
# 注意:需先于 CredentialService / WizardService 构造(依赖关系)。
qr_login_service = QrLoginService(
login_adapter_registry=login_adapter_registry,
logger=adapters.logger,
config_port=adapters.config,
config_manager=config_manager,
)
# 4.7.2 凭证编排服务Task 11 DI 装配)
# 渠道账号凭证的唯一落库入口,依赖 QrLoginServiceQR 凭证获取)+
# ConfigPort加密存储+ CachePort缓存失效+ PersistencePort
# P1 聚合根持久化)+ LoggerPort。必须在 QrLoginService 之后构造
# (强依赖),经 ControlPlanePipeline.create 注入到 AccountHandler
# P1 enable/disable 链路 OFFLINE→ONLINE 凭证存在性校验)。
# WizardService 的 P2 finalize 凭证落库为未来规划,当前未消费。
credential_service = CredentialService(
config_port=adapters.config,
config_manager=config_manager,
persistence_port=adapters.persistence,
qr_login_service=qr_login_service,
cache_port=adapters.cache,
logger_port=adapters.logger,
)
# 4.7.3 安装向导领域服务FR-16
# 协调 WizardAdapter 与 ConfigPort编排向导步骤查询、校验、应用、
# 配置聚合与 OAuth 回调。向导状态持久化到 ConfigPort 的 CHANNEL 作用域。
wizard_service = WizardService(
wizard_adapter_registry=wizard_adapter_registry,
config_port=adapters.config,
config_manager=config_manager,
logger=adapters.logger,
)
# 4.7.4 配置诊断领域服务FR-17
# 协调 DoctorAdapter 与 ConfigPort编排诊断检查项查询、单项检查、
# 全量检查与自动修复。已应用迁移列表从 CHANNEL 作用域读取AC-64
# 单项检查异常隔离不中断整体诊断报告。
doctor_service = DoctorService(
doctor_adapter_registry=doctor_adapter_registry,
config_port=adapters.config,
logger=adapters.logger,
whitelist_registry=whitelist_registry,
)
# 4.7.5 账户生命周期领域服务AL-01~AL-04
# 协调 LifecycleAdapter编排账户 ID 解析、配置规范化与生命周期回调
# afterAccountConfigWritten / beforeAccountDelete / onAccountEnabled /
# onAccountDisabled。注入到 ControlPlanePipeline 的 lifecycle_service
# 阶段。
account_lifecycle_service = AccountLifecycleService(
lifecycle_adapter_registry=lifecycle_adapter_registry,
logger=adapters.logger,
)
# 4.8 控制面管道
# DispatchStage 不再依赖 AdminMessagePort / HealthAggregatorPort —— 前者
# 由 AdminMessageService 独立装配(见 4.6),后者由 HealthCheckService
# 独立持有(见 5. HealthCheckService 装配),控制面 dispatch 阶段不涉及
# 这两类职责。
# 消息操作被驱动适配器MSG-05 撤回用例):复用 4.1 收集的
# message_ops_adapter_registry按 channel_type 路由到对应插件适配器,
# 通过 ControlPlanePipeline.create 透传至 DispatchStage。
message_ops_port_adapter = MessageOpsPortAdapter(
message_ops_adapter_registry=message_ops_adapter_registry,
logger=adapters.logger,
)
# 4.7.5 内容审核域装配CR-01~CR-03
# content_moderation_adapter_registry 在 4.1 收集循环中已构建,
# 同 channel_type 注册多个实现时抛 RuleViolationErrorINV-7 错误
# 显式化,不静默兜底)。未注册时为空 dict使用兜底适配器。
# ContentReviewQueryService 装配(数据面,不经控制面管道):
# 直接读取 review_repositoryContentReviewRepositoryPort覆盖 CR-02
# 历史列表与 CR-03 历史详情两个查询端点。查询无副作用,不写审计日志。
content_review_query_service = ContentReviewQueryService(
review_repository=review_repository,
logger=adapters.logger,
)
# 报告域依赖RPT-05~RPT-ONEOFF-02
# - report_repository报告记录仓储注入 DispatchStage 供 reports/* 读写
# - scheduler_service调度器服务注入 DispatchStage 供 reports/create_oneoff
# 创建一次性任务schedule_kind="at"api 进程仅创建任务记录worker
# 进程执行时通过 ChannelReportHandler 生成报告内容
report_repository = SqlAlchemyReportRepositoryAdapter(db, adapters.logger)
scheduler_service = create_scheduler_service(db, arq_pool=arq_pool)
# 渠道主动探测器FR-35供 account/runtime_status 聚合探测状态使用。
# 依赖均为请求级端口,随请求构造以保证端口引用与当前 db session 一致。
channel_probe = ChannelProbe(
plugin_registry=plugin_registry,
persistence_port=adapters.persistence,
cache_port=adapters.cache,
queue_port=queue_port,
logger=adapters.logger,
)
control_plane_pipeline = ControlPlanePipeline.create(
persistence_port=adapters.persistence,
config_manager=config_manager,
session_merger=session_merger,
degradation_manager=degradation_manager,
whitelist_registry=whitelist_registry,
cache_port=adapters.cache,
event_publisher=event_publisher,
plugin_registry=plugin_registry,
wizard_service=wizard_service,
directory_adapter_registry=directory_adapter_registry,
doctor_service=doctor_service,
whitelist_adapter_registry=whitelist_adapter_registry,
logger=adapters.logger,
lifecycle_service=account_lifecycle_service,
login_service=qr_login_service,
conversation_port=adapters.conversation,
lifecycle_manager=plugin_lifecycle_manager,
circuit_breaker=channel_circuit_breaker,
message_ops_port=message_ops_port_adapter,
outbox_repository=adapters.persistence,
outbox_config=outbox_config,
outbox_config_holder=outbox_config_holder,
queue_port=queue_port,
content_moderation_adapters=content_moderation_adapter_registry,
default_moderation_adapter=default_moderation_adapter,
review_repository=review_repository,
report_repository=report_repository,
scheduler_service=scheduler_service,
masking_port=adapters.masking,
transaction_port=adapters.transaction,
plugin_loader=plugin_loader,
webhook_test_adapters=webhook_test_adapter_registry,
attachment_upload_adapters=attachment_upload_adapter_registry,
channel_probe=channel_probe,
realtime_metrics=realtime_metrics,
service_account_port=service_account_port,
# Task 11: 凭证编排服务,供 AccountHandler P1 enable/disable 链路
# 凭证存在性校验OFFLINE→ONLINE 时 getCredentials
credential_service=credential_service,
)
# 5. 用例服务(请求级,注入管道与适配器)
# PluginLifecycleManager / HealthAggregator 为应用级单例,从 DI 容器
# resolve 后注入用例服务,类型安全,不使用 Any。
# AuditContextBuilder 集中审计日志构造逻辑D5供 ChannelControlService
# 在管道失败时通过独立事务记录失败审计日志AC-32。audit_log_repo 取
# 自 persistence 聚合适名(继承 AuditLogRepositoryPort
audit_context_builder = AuditContextBuilder(
audit_log_repo=adapters.persistence,
logger=adapters.logger,
masking_port=adapters.masking,
)
channel_control = ChannelControlService(
control_plane_pipeline=control_plane_pipeline,
transaction_port=adapters.transaction,
audit_context_builder=audit_context_builder,
logger=adapters.logger,
user_identity_repository=adapters.persistence,
session_repository=adapters.persistence,
config_port=adapters.config,
service_account_port=adapters.service_account,
session_merger=session_merger,
)
# 5.1 注入 ChannelControlService 作为 WhitelistCommandPort 实现FR-15 / FR-18
# ChannelControlService 同时实现 WhitelistManagementPort 与
# WhitelistCommandPort后者将 /allowlist 命令按 action 分派到
# listWhitelist / addWhitelistEntry / removeWhitelistEntry 类型化方法。
# CommonCommandAdapter 先于 ChannelControlService 构造,通过 setter
# 注入解决装配顺序(与 ChannelToolExecutor.setMessageOperationExecutor
# 同模式)。
common_command_adapter.setWhitelistCommandPort(channel_control)
return ChannelUseCases(
inbound_message=InboundMessageService(
inbound_pipeline=inbound_pipeline,
outbound_pipeline=outbound_pipeline,
config_port=adapters.config,
logger=adapters.logger,
tracer=adapters.tracer,
transaction_port=adapters.transaction,
account_repository=adapters.persistence,
ack_decision_maker=ack_decision_maker,
inbound_adapter_registry=inbound_adapter_registry,
),
admin_message=admin_message_service,
plugin_lifecycle=PluginLifecycleService(
lifecycle_manager=plugin_lifecycle_manager,
logger=adapters.logger,
),
health_check=HealthCheckService(
health_aggregator=health_aggregator,
cache_port=adapters.cache,
logger=adapters.logger,
tracer_port=adapters.tracer,
account_repository=adapters.persistence,
audit_log_repo=adapters.persistence,
),
channel_tool_executor=channel_tool_executor,
# ChannelControlService 实现 HealthCheckPort 的控制面子集
# getSingleHealth / probeChannelDeep绑定同一实例。
health_check_control=channel_control,
# ChannelControlService 同时实现以下 19 个类型化领域端口,组合根将
# 同一实例绑定到各字段(窄端口依赖)。
wizard=channel_control,
doctor=channel_control,
whitelist_management=channel_control,
directory=channel_control,
pairing_management=channel_control,
config_management=channel_control,
session_management=channel_control,
user_binding=channel_control,
audit_query=channel_control,
account_management=channel_control,
login=channel_control,
message_management=channel_control,
plugin_management=channel_control,
outbox_management=channel_control,
capability_query=channel_control,
# ChannelControlService 同时实现 ContentReviewPort第 16 个类型化
# 端口),组合根将同一实例绑定到 content_review 字段。
content_review=channel_control,
# ContentReviewQueryService 为独立用例服务(数据面,不经控制面管道),
# 直接读取 review_repository 实现 CR-02 / CR-03 查询。
content_review_query=content_review_query_service,
dashboard_view=channel_control,
report_management=channel_control,
analytics_view=channel_control,
)
def create_channel_report_handler_dependencies(
session_factory: Any,
) -> dict[str, Any]:
"""构造 ChannelReportHandler 依赖字典worker 进程装配用)。
由 ``infrastructure/scheduler.py`` 的 ``register_scheduler_handlers``
调用,传入 worker 进程级 ``session_factory``,返回 ``ChannelReportHandler.__init__``
所需的依赖字典。
**端口装配说明**``AnalyticsViewPort``18 号文档)与 ``DashboardViewPort``
16 号文档)已在 api 进程装配(见 ``create_channel_use_cases``),但
worker 进程由于不持有 DI 容器与请求级 DB 会话,当前注入 ``None``。
``ChannelReportHandler._generateReportContent`` 对 None 端口抛
``NotImplementedError``,报告状态变 ``failed``。待 worker 进程装配
端口实例后即可激活异步报告生成。
依赖方向合规INV-1``report_repo_factory`` 在 infrastructure 层
装配具体适配器 ``SqlAlchemyReportRepositoryAdapter``,应用层 handler
仅依赖 ``ReportRepositoryPort`` 抽象,不直接 import 适配器实现。
Args:
session_factory: 调用返回 ``AsyncSession`` 的异步上下文管理器工厂,
通常为 ``pg_manager.get_async_session_context``。
Returns:
依赖字典key 与 ``ChannelReportHandler.__init__`` 参数名一致:
``{"session_factory": ..., "report_repo_factory": ...,
"analytics_view_port": None, "dashboard_view_port": None,
"logger": ...}``
"""
# StructuredLoggerAdapter 包装默认 loguru logger 以满足 LoggerPort 协议
# (对齐 create_driven_adapters 中 _logger_adapter 的装配模式,注入
# MaskingAdapter 以满足 LoggerPort 协议的脱敏要求)
logger_port = _create_worker_logger_port()
# 报告仓储工厂infrastructure 层装配具体适配器handler 仅依赖端口抽象。
# 每次执行通过 session_factory 创建独立 db 会话后调用本工厂得到端口实例,
# 保证会话隔离(避免 worker 进程长生命周期会话问题)。
def report_repo_factory(db: AsyncSession) -> ReportRepositoryPort:
return SqlAlchemyReportRepositoryAdapter(db, logger_port)
return {
"session_factory": session_factory,
"report_repo_factory": report_repo_factory,
# AnalyticsViewPort / DashboardViewPort 已在 api 进程装配,
# worker 进程因不持有 DI 容器与请求级 DB 会话,暂注入 None。
# ChannelReportHandler 对 None 端口抛 NotImplementedError
# 报告状态变 failed。待 worker 装配端口实例后激活。
"analytics_view_port": None,
"dashboard_view_port": None,
"logger": logger_port,
}
def _create_worker_logger_port() -> Any:
"""构造 worker 进程级 LoggerPort 实例。
复用无状态 ``MaskingAdapter`` + ``StructuredLoggerAdapter`` 装配模式,
对齐 ``adapters/__init__.py`` 中 ``_logger_adapter`` 的构造方式
(注入 ``masking_port`` 以满足 ``LoggerPort`` 协议的脱敏要求)。
"""
from yuxi.channels.adapters.masking_adapter import MaskingAdapter
from yuxi.channels.adapters.structured_logger_adapter import (
StructuredLoggerAdapter,
)
return StructuredLoggerAdapter(masking_port=MaskingAdapter())
def _create_outbox_config() -> OutboxConfig:
"""从全局配置源构造 OutboxConfig供 ChannelPersistenceAdapter 构造使用)。
对齐 ``create_channel_use_cases`` 中 OutboxConfig 的构造方式,消除应用层
对 ``yuxi.config.app`` 的直接依赖§6.1 应用服务层禁止依赖具体技术适配器)。
"""
return OutboxConfig(
ttl_seconds=app_config.channel_outbox_ttl_seconds,
retry_backoff_schedule=tuple(app_config.channel_outbox_retry_backoff_schedule),
max_retry=app_config.channel_outbox_max_retry,
)
def create_channel_session_inactive_cleanup_handler_dependencies(
session_factory: Any,
) -> dict[str, Any]:
"""构造 ChannelSessionInactiveCleanupHandler 依赖字典worker 进程装配用)。
由 ``infrastructure/scheduler.py`` 的 ``register_scheduler_handlers``
调用,传入 worker 进程级 ``session_factory``,返回
``ChannelSessionInactiveCleanupHandler.__init__`` 所需的依赖字典。
依赖方向合规INV-1``session_repo_factory`` 在 infrastructure 层
装配具体适配器 ``ChannelPersistenceAdapter``fat adapter实现
``ChannelSessionRepositoryPort``),应用层 handler 仅依赖端口抽象,
不直接 import 适配器实现。
Args:
session_factory: 调用返回 ``AsyncSession`` 的异步上下文管理器工厂,
通常为 ``pg_manager.get_async_session_context``。
Returns:
依赖字典key 与 ``ChannelSessionInactiveCleanupHandler.__init__``
参数名一致:``{"session_factory": ..., "session_repo_factory": ...,
"logger": ...}``
"""
from yuxi.channels.adapters.channel_persistence_adapter import (
ChannelPersistenceAdapter,
)
logger_port = _create_worker_logger_port()
outbox_config = _create_outbox_config()
def session_repo_factory(db: AsyncSession) -> ChannelSessionRepositoryPort:
return ChannelPersistenceAdapter(db, outbox_config=outbox_config, logger=logger_port)
return {
"session_factory": session_factory,
"session_repo_factory": session_repo_factory,
"logger": logger_port,
}
def create_channel_outbox_terminal_cleanup_handler_dependencies(
session_factory: Any,
) -> dict[str, Any]:
"""构造 ChannelOutboxTerminalCleanupHandler 依赖字典worker 进程装配用)。
``event_publisher`` 注入 ``None``worker 进程未注入事件发布端口,
handler 内 best-effort 发布 ``OutboxEntryPurgedEvent``,发布失败仅记录
WARN 不影响清理主流程,对齐 ``ChannelReportHandler`` 的
``analytics_view_port=None`` 模式)。
Args:
session_factory: 调用返回 ``AsyncSession`` 的异步上下文管理器工厂。
Returns:
依赖字典key 与 ``ChannelOutboxTerminalCleanupHandler.__init__``
参数名一致。
"""
from yuxi.channels.adapters.channel_persistence_adapter import (
ChannelPersistenceAdapter,
)
logger_port = _create_worker_logger_port()
outbox_config = _create_outbox_config()
def outbox_repo_factory(db: AsyncSession) -> OutboxRepositoryPort:
return ChannelPersistenceAdapter(db, outbox_config=outbox_config, logger=logger_port)
return {
"session_factory": session_factory,
"outbox_repo_factory": outbox_repo_factory,
"event_publisher": None, # worker 进程未注入事件发布端口best-effort
"logger": logger_port,
}
def create_channel_pairing_terminal_cleanup_handler_dependencies(
session_factory: Any,
) -> dict[str, Any]:
"""构造 ChannelPairingTerminalCleanupHandler 依赖字典worker 进程装配用)。
Args:
session_factory: 调用返回 ``AsyncSession`` 的异步上下文管理器工厂。
Returns:
依赖字典key 与 ``ChannelPairingTerminalCleanupHandler.__init__``
参数名一致。
"""
from yuxi.channels.adapters.channel_persistence_adapter import (
ChannelPersistenceAdapter,
)
logger_port = _create_worker_logger_port()
outbox_config = _create_outbox_config()
def pairing_repo_factory(db: AsyncSession) -> PairingRepositoryPort:
return ChannelPersistenceAdapter(db, outbox_config=outbox_config, logger=logger_port)
return {
"session_factory": session_factory,
"pairing_repo_factory": pairing_repo_factory,
"logger": logger_port,
}
def create_channel_report_cleanup_handler_dependencies(
session_factory: Any,
) -> dict[str, Any]:
"""构造 ChannelReportCleanupHandler 依赖字典worker 进程装配用)。
复用 ``create_channel_report_handler_dependencies`` 的 ``report_repo_factory``
装配模式(``SqlAlchemyReportRepositoryAdapter``),仅在 logger 构造上
统一为 ``_create_worker_logger_port``(注入 ``masking_port``)。
Args:
session_factory: 调用返回 ``AsyncSession`` 的异步上下文管理器工厂。
Returns:
依赖字典key 与 ``ChannelReportCleanupHandler.__init__``
参数名一致。
"""
logger_port = _create_worker_logger_port()
def report_repo_factory(db: AsyncSession) -> ReportRepositoryPort:
return SqlAlchemyReportRepositoryAdapter(db, logger_port)
return {
"session_factory": session_factory,
"report_repo_factory": report_repo_factory,
"logger": logger_port,
}