rule

package
v0.0.1-beta.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package rule 实现规则引擎(可编排状态管理):事件 → 有界 channel → 规则 worker (priority 首中匹配)→ 状态/冷却/权重更新。scheduler.MarkResult 的硬编码状态机 由本包替代:scheduler 只做禁用守卫 + 事件投递(条件投递),动作应用经 SetApply 注册的回调完成(更新快照 + EWMA + 异步回写,属 scheduler 侧)。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Apply

func Apply(t domain.RuleThen, ev Event) (*domain.AccountStatus, *time.Time, *int)

Apply 解析 then 动作:cooldownUntil = OccurredAt + 解析后的 cooldown; cooldown 未配但事件带 ResetAt 时用 ResetAt(M2 残留:resetAt 语义保留)。 Status 为 nil 返回 nil 状态 = 只改权重(或只改冷却)。

func Match

func Match(w domain.RuleWhen, ev Event, wc windowSnapshot) bool

Match 规则 when 与事件(+ 窗口计数)是否匹配:等值/子串/计数阈值/比例。 窗口比例 = t429(或 failure) / (ok+failure+t429),仅当 total ≥ CountTotalGE 时参与判定(样本不足不满足,ValidateWhen 已保证比例类必配 CountTotalGE, 此处仍防御)。

func UnifiedMessage

func UnifiedMessage(then domain.RuleThen, upstream string) (string, bool)

UnifiedMessage 统一公式 msg=CustomMessage!=nil?*CustomMessage:upstream 响应与 sanitize 同源(I-3),代理日志保留原文边界另述 TODO: upstream param unused — kept for formula parity (honest return would be upstream when CustomMessage==nil; callers currently handle passthrough separately)

func ValidateThen

func ValidateThen(t domain.RuleThen) error

ValidateThen then 动作校验:全空 Then{} 合法=纯透传(匹配后码/文双透、上游原样返回、零惩罚); 其余:status 合法枚举;cooldown 可 time.ParseDuration 解析且 > 0;weight ∈ [0,100]; ResponseCode!=nil 需 400-599;CustomMessage==ptr("") 拒绝。指针即意图,nil=透传; seed-4xx-400 直插 store 的 Then{} 与用户规则 Then{} 语义等价(零惩罚全透)。

func ValidateWhen

func ValidateWhen(w domain.RuleWhen) error

ValidateWhen when 语义校验(字段白名单/未知字段由 service 层 JSON 反序列化 DisallowUnknownFields 挡下;此处查语义):

  • kind 必须为 ok/429/4xx/5xx/network 之一(error 已删除——4xx 独立、 连接级独立 network,用户裁决)
  • kind=ok 与 error_message_contains 不兼容(ok 事件错误信息恒空 → 永不命中)
  • 计数阈值 ≥ 0、window_seconds ≥ 1
  • 比例 ∈ [0,1] 且必须配 count_total_ge(比例样本下限)

Types

type ApplyFunc

type ApplyFunc func(aid int64, st *domain.AccountStatus, cooldownUntil *time.Time, weight *int, errMsg string)

ApplyFunc 动作应用回调(由 scheduler 注册):st 为 nil = 不改状态(只改权重); cooldownUntil 为 nil = 不设冷却;weight 为 nil = 不改权重。errMsg 为事件 错误文本(error_message_contains 已匹配;供 last_error 落库——部署故障 修复:scheduler 侧截断 500 后回写)。

type Config

type Config struct {
	EventQueueSize int // 事件队列容量,默认 4096
}

Config 引擎配置。

type Event

type Event struct {
	AccountID    int64
	TemplateID   int64
	GroupID      *int64
	Model        string
	Kind         Kind
	HTTPStatus   *int
	ErrorMessage string
	ResetAt      *time.Time
	OccurredAt   time.Time // 零值由引擎填充为当前时间
}

Event 请求结果事件(由 scheduler.MarkResult 构造投递)。

type Kind

type Kind int

Kind 事件类别(单一 kind 概念;连接级/5xx 分流由 scheduler.RuleKindOf 在 调用点完成——scheduler 不再有第二套枚举)。

const (
	KindOK Kind = iota
	Kind429
	Kind4xx
	Kind5xx
	KindNetwork // 连接级(code==0)事件——独立类型,不吃 5xx 冷却(用户裁决)
)

func (Kind) String

func (k Kind) String() string

type RuleEngine

type RuleEngine struct {
	// contains filtered or unexported fields
}

RuleEngine 规则引擎:加载 enabled 规则(priority 升序)、逐规则首中匹配、 窗口计数维护与 worker 消费循环(Name/Start/Close 见 worker.go)。

func New

func New(cfg Config, store repository.RuleStore, log *logx.Logger) *RuleEngine

New 只建结构(不加载规则、不注册 apply——分别由 Reload/SetApply 显式完成)。

func (*RuleEngine) Classify

func (e *RuleEngine) Classify(ev Event) (then domain.RuleThen, punish bool)

Classify 事件分类决策(错误分支响应/投递决策——scheduler 包装调用,用户面 err_logs 行级脱敏亦复用):遍历 enabled 规则(priority 升序首中),首个 "非窗口条件维度"(kind/http_status/message_contains/account/template/group/ model)命中者决定结果。窗口条件规则(count_*/ratio_*,ruleNeedsWindow)依赖 历史计数,预判不可得——按"可能命中"保守处理(不参与判定,窗口阈值由 worker Match 精确裁决;prejudge 命中 → punish 保证事件投递,worker 再精确应用)。 指针即意图:then.ResponseCode nil=透传上游码,non-nil=覆写;then.CustomMessage nil=透传上游文,non-nil=覆写;头透传与 kind 解耦(ResponseCode==nil 才透)。 返回 then 值拷贝(调用方只读不得修改)与 punish(true = 命中规则有状态动作 Status/Weight/Cooldown 任一非 nil——应投递 MarkResult;漏判 Cooldown 则 cooldown-only 规则永不投递,冷却静默丢弃, 2026-08-19 缺陷 1 根因)。无命中 → (domain.RuleThen{}, false)(默认归一 502+generic,安全默认 ——不认识的错误不透传)。 零分配:仅读规则集切片(RLock 快照)+ 字符串比较。

func (*RuleEngine) Close

func (e *RuleEngine) Close(ctx context.Context) error

Close 排空剩余事件(限时,复用 scheduler.Close 模式);幂等, 未 Start 时也可安全排空。循环本身随 Start 的 ctx 取消而退出。

func (*RuleEngine) Enqueue

func (e *RuleEngine) Enqueue(ev Event)

Enqueue 投递事件:有界 channel,满则丢弃(dropped 原子计数)。热点修复 B: 逐条 Warn → 阈值告警(errlog 同构)——丢弃累计 ≥ ruleDropWarnThreshold 且 边沿未告警 → Warn 恰好一次(带累计数),不再刷屏。热路径纪律:丢弃路径 仅两个原子操作(Add + CompareAndSwap),零分配;日志只在阈值跨越时产生。

func (*RuleEngine) Flush

func (e *RuleEngine) Flush(ctx context.Context)

Flush 同步排空队列:处理完当前队列中的全部事件后返回(测试与优雅关闭用)。 幂等,未 Start 时也可安全排空。

func (*RuleEngine) HandleEvent

func (e *RuleEngine) HandleEvent(ctx context.Context, ev Event)

HandleEvent 同步处理单个事件:窗口计数 → 逐规则 Match(首中)→ ApplyFunc。 worker 消费循环与测试共用。命中不清零窗口计数(C2)——滑动自然衰减, 升级阶梯(如 60s 内 ≥5 error → 更重惩罚)不被低阈值规则清零阻断。 未命中仅更新计数。

func (*RuleEngine) Name

func (e *RuleEngine) Name() string

Name 满足 worker.Worker 契约(Global Constraints #5)。

func (*RuleEngine) NeedsOKEvents

func (e *RuleEngine) NeedsOKEvents() bool

NeedsOKEvents 规则表中是否存在需要 ok 事件投递的规则(when.kind 为 nil 或 "ok")—— scheduler 据此条件投递(C1:种子恢复规则 kind=ok 必须投递,否则成功恢复永不触发)。

func (*RuleEngine) Reload

func (e *RuleEngine) Reload(ctx context.Context) error

Reload 全量加载 enabled 规则(priority 升序);空表先写种子(seedRules)。 失败返回 error——规则表是状态管理唯一路径,main 收到错误即 fatalf。

func (*RuleEngine) ReloadRules

func (e *RuleEngine) ReloadRules(ctx context.Context) error

ReloadRules 规则表全量重载(invalidate.RulesReloader 适配,#14 T3a 装配 invalidate.Config.Rules):与 Reload 同一实现——重载清窗口计数,全实例同步 执行语义(设计文档 §1.5,NOTIFY Rules:true 远端变更触发)。

func (*RuleEngine) SetApply

func (e *RuleEngine) SetApply(fn ApplyFunc)

SetApply 注册动作应用回调(scheduler 构造期注入;可重复调用覆盖)。

func (*RuleEngine) Start

func (e *RuleEngine) Start(ctx context.Context) error

Start 启动事件消费循环(含周期性窗口清理);重复 Start 返回错误(幂等)。

func (*RuleEngine) Stats

func (e *RuleEngine) Stats() any

Stats 满足 handler.StatsProvider(独立于 worker.Worker 契约;装配链路见 internal/handler/ops.go 文件头)。

type RuleEngineStats

type RuleEngineStats struct {
	Queued            int   `json:"queued"`              // 队列积压事件数
	QueueCap          int   `json:"queue_cap"`           // 事件队列容量(丢弃阈值)
	Dropped           int64 `json:"dropped"`             // 队列满丢弃累计(atomic.Uint64 转 int64——JSON 数字精度)
	DropWarnThreshold int64 `json:"drop_warn_threshold"` // 丢弃告警阈值(包级 var 直读)
}

RuleEngineStats 规则引擎状态(队列占用 + 事件丢弃累计)。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL