ForcePilot/backend/package/yuxi/channel/constants.py
Kris bab30f2715
Some checks failed
Deploy VitePress site to Pages / build (push) Has been cancelled
Ruff Format Check / Ruff Format & Lint (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
feat:0715
2026-07-15 12:30:58 +08:00

109 lines
3.3 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.

"""多渠道网关共享常量与 Redis Key 模板。"""
from __future__ import annotations
from enum import StrEnum
class UserChannelType(StrEnum):
"""用户渠道来源类型。"""
FEISHU = "feishu"
DINGTALK = "dingtalk"
WECOM = "wecom"
SLACK = "slack"
TELEGRAM = "telegram"
OPEN_API = "open_api"
MANUAL = "manual"
SSO = "sso"
class DeliveryStatus(StrEnum):
"""消息投递状态。"""
COMPLETE = "complete"
PARTIAL_FAILED = "partial_failed"
FAILED = "failed"
DEAD_LETTER = "dead_letter"
PENDING = "pending"
class DispatchResult(StrEnum):
"""出站调度结果。"""
SUCCESS = "success"
PERMANENT_FAILURE = "permanent_failure"
RETRYABLE = "retryable"
class InboundRejectionReason(StrEnum):
"""入站消息拒绝原因。"""
DUPLICATE = "duplicate"
UNKNOWN_CHANNEL = "unknown_channel"
CONFIG_ERROR = "config_error"
SECURITY_REJECTED = "security_rejected"
DM_NOT_ALLOWED = "dm_not_allowed"
DM_PAIRING_REQUIRED = "dm_pairing_required"
GROUP_NOT_ALLOWED = "group_not_allowed"
BOT_LOOP_DETECTED = "bot_loop_detected"
RATE_LIMITED = "rate_limited"
INTERNAL_ERROR = "internal_error"
# Redis Stream
CHANNEL_STREAM_KEY = "ch:messages"
CHANNEL_CONSUMER_GROUP = "ch:dispatchers"
# Redis Pub/Sub
CHANNEL_CONFIG_CHANGE_CHANNEL = "ch:config:changed"
# Redis Key 模板
CHANNEL_PROCESSED_KEY_TEMPLATE = "ch:processed:{message_id}"
CHANNEL_DELIVERED_KEY_TEMPLATE = "ch:delivered:{message_id}"
CHANNEL_PROCESSING_KEY_TEMPLATE = "ch:processing:{message_id}"
CHANNEL_PUBLISHING_KEY_TEMPLATE = "ch:publishing:{message_id}"
CHANNEL_COMPENSATE_LOCK_KEY = "ch:compensate:lock"
CHANNEL_RATE_LIMIT_KEY_TEMPLATE = "ch:rate:{channel_type}:{account_id}:{actor_id}"
# TTL / 时间常量(秒)
CHANNEL_DELIVERED_TTL_SECONDS = 7 * 24 * 3600 # 已投递标记保留 7 天
CHANNEL_PROCESSING_LOCK_TTL_SECONDS = 300 # processing 锁初始 TTL
CHANNEL_PROCESSING_LOCK_RENEW_INTERVAL_SECONDS = 60 # 锁续期间隔
CHANNEL_PUBLISHING_LOCK_TTL_SECONDS = 300
CHANNEL_PROCESSED_TTL_SECONDS = 300 # 入站去重默认 TTL
CHANNEL_COMPENSATE_LOCK_TTL_SECONDS = 300
# 指数退避
CHANNEL_MAX_DELIVERY_ATTEMPTS = 5
CHANNEL_MAX_COMPENSATE_ATTEMPTS = 5
CHANNEL_BACKOFF_BASE_SECONDS = 2
CHANNEL_BACKOFF_MAX_SECONDS = 3600
# 消息认领pending 条目空闲多久后视为死消费者(毫秒)
CHANNEL_PENDING_CLAIM_MIN_IDLE_MS = (CHANNEL_PROCESSING_LOCK_TTL_SECONDS + 10) * 1000
def channel_processed_key(message_id: str | int | None) -> str:
return CHANNEL_PROCESSED_KEY_TEMPLATE.format(message_id=message_id or "unknown")
def channel_delivered_key(message_id: str | int | None) -> str:
return CHANNEL_DELIVERED_KEY_TEMPLATE.format(message_id=message_id or "unknown")
def channel_processing_key(message_id: str | int | None) -> str:
return CHANNEL_PROCESSING_KEY_TEMPLATE.format(message_id=message_id or "unknown")
def channel_publishing_key(message_id: str | int | None) -> str:
return CHANNEL_PUBLISHING_KEY_TEMPLATE.format(message_id=message_id or "unknown")
def channel_rate_limit_key(channel_type: str, account_id: str, actor_id: str) -> str:
return CHANNEL_RATE_LIMIT_KEY_TEMPLATE.format(
channel_type=channel_type,
account_id=account_id,
actor_id=actor_id,
)