/** * 队列 / Outbox 投递协议常量(技术架构 §2.4 / §3.7,A6-BE-02 / A6-BE-05 / A6-INF-01)。 * * key 统一 `lingxi:` 前缀;心跳 key 与 worker 侧(apps/worker/src/heartbeat.ts)保持一致, * 跨 app 契约变更时必须两端同步。 */ /** Outbox 投递分布式锁:同一时刻只允许一个 dispatcher 抢到本轮投递权 */ export const OUTBOX_DISPATCH_LOCK_KEY = 'lingxi:lock:outbox-dispatch'; /** 锁 TTL:既覆盖单轮投递耗时,又保证实例崩溃后 5s 内可被其他实例接管 */ export const OUTBOX_DISPATCH_LOCK_TTL_MS = 5_000; /** 单轮最多认领的事件数(避免一轮占满连接 / 内存) */ export const OUTBOX_DISPATCH_BATCH_SIZE = 20; /** 死信阈值:投递尝试达到该次数后标记 dead_lettered,避免单条事件永久阻塞 outbox 表 */ export const OUTBOX_MAX_ATTEMPTS = 10; /** 默认调度间隔(可被环境变量 OUTBOX_DISPATCH_INTERVAL_MS 覆盖) */ export const OUTBOX_DISPATCH_DEFAULT_INTERVAL_MS = 1_000; /** 死信标记:写入 outbox_events.last_error,便于监控与人工排查 */ export const OUTBOX_DEAD_LETTER_MARKER = 'dead_lettered'; /** worker 心跳 key 前缀:`lingxi:worker:heartbeat:` */ export const WORKER_HEARTBEAT_KEY_PREFIX = 'lingxi:worker:heartbeat:'; /** worker 心跳 TTL(秒);worker 每 10s 续写一次,超过 TTL 视为心跳缺失 */ export const WORKER_HEARTBEAT_TTL_SECONDS = 30; /** 心跳年龄超过 TTL 的倍数视为陈旧(用于健康检查降级判定) */ export const WORKER_HEARTBEAT_STALE_MULTIPLIER = 2; /** 单轮投递 / 单次队列命令的超时,避免 Redis 异常时无限挂起 */ export const QUEUE_OPERATION_TIMEOUT_MS = 5_000; /** Lua:仅当锁 value 与 token 相等时释放,避免误删其他实例持有的锁 */ export const RELEASE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";