ForcePilot/backend/server/channel_worker_main.py
Kris 9a8a27bf36 feat(channel): 新增渠道网关模块完整实现
本次提交新增了完整的多渠道消息网关系统,包括:
1. 支持飞书、钉钉、Web、Hook 四种渠道的适配器与配置
2. 领域模型层:消息、会话、绑定、出箱等核心实体
3. 应用服务层:管道、中间件、DTO 与业务逻辑
4. 基础设施层:持久化、过滤器、队列等端口实现
5. 接口层:REST API、SSE、WebSocket 通信端点
6. 前端页面与路由配置,添加渠道管理菜单
7. 新增相关依赖包与 docker-compose 部署配置
2026-05-30 21:53:09 +08:00

99 lines
2.9 KiB
Python

"""Channel worker entrypoint with embedded health endpoint."""
from __future__ import annotations
import asyncio
import os
import signal
import sys
if sys.platform == "win32":
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
from aiohttp import web
from yuxi.channel.infrastructure.agent.agent_adapter import AgentAdapter
from yuxi.channel.startup import init_channel, shutdown_channel
from yuxi.storage.postgres.manager import pg_manager
from yuxi.utils.logging_config import logger
_HEALTH_PORT = int(os.getenv("CHANNEL_HEALTH_PORT", "5051"))
async def _health_handler(request: web.Request) -> web.Response:
checks: dict[str, str] = {"status": "ok"}
container = request.app["container"]
try:
redis = container.cache_port
await redis.ping()
checks["redis"] = "ok"
except Exception as e:
checks["redis"] = f"error: {e}"
checks["status"] = "degraded"
worker_pool = getattr(container, "worker_pool", None)
if worker_pool and getattr(worker_pool, "is_running", False):
checks["worker_pool"] = "ok"
else:
checks["worker_pool"] = "not_running"
checks["status"] = "degraded"
status_code = 200 if checks["status"] == "ok" else 503
return web.json_response(checks, status=status_code)
async def _start_health_server(container: object) -> web.AppRunner:
app = web.Application()
app["container"] = container
app.router.add_get("/healthz", _health_handler)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, "0.0.0.0", _HEALTH_PORT)
await site.start()
logger.info("health endpoint started on port %d", _HEALTH_PORT)
return runner
async def main():
redis_url = os.getenv("REDIS_URL", "redis://redis:6379/0")
config_path = os.getenv("CHANNEL_CONFIG_PATH", "channel_config.yaml")
logger.info("starting channel worker, redis=%s", redis_url)
container = await init_channel(
redis_url=redis_url,
agent_port=AgentAdapter(pg_manager.get_async_session_context),
config_yaml_path=config_path,
)
health_runner = await _start_health_server(container)
stop_event = asyncio.Event()
def _signal_handler():
stop_event.set()
loop = asyncio.get_running_loop()
if sys.platform == "win32":
for sig in (signal.SIGINT, signal.SIGTERM):
signal.signal(sig, lambda *_: _signal_handler())
else:
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, _signal_handler)
logger.info("channel worker running, waiting for stop signal")
await stop_event.wait()
await health_runner.cleanup()
logger.info("health endpoint stopped")
await shutdown_channel(container)
logger.info("channel worker stopped")
if __name__ == "__main__":
asyncio.run(main())