diff --git a/models/pbl_runtime_event.json b/models/pbl_runtime_event.json index e3c2929..c15b3b9 100644 --- a/models/pbl_runtime_event.json +++ b/models/pbl_runtime_event.json @@ -2,138 +2,78 @@ "summary": [ { "name": "pbl_runtime_event", - "comment": "运行时事件(append-only,按月 RANGE 分区)", + "title": "运行时事件流(append-only)", + "comment": "运行时事件流:append-only(禁 UPDATE/DELETE,由存储过程 pbl_assert_append_only + BEFORE UPDATE/BEFORE DELETE 触发器强制),按 created_at 做按月 RANGE COLUMNS(created_at) 分区(分区键禁 TIMESTAMP,故用 DATETIME),分区保留 14 个月(超期由维护过程 DROP PARTITION)。物理主键必须为复合主键 (id, created_at) —— MySQL/MariaDB 要求分区表的所有唯一键(含主键)必须包含分区列,否则建表报错 1503;id 仍是逻辑主键与自增列。本 json 与 scripts/pbl_runtime_event_ddl.py 的 COLUMNS/PRIMARY_KEY/UNIQUE_KEYS/SECONDARY_KEYS 为同一真源的两个视图,DDL 侧为权威派生源(列顺序=物理列顺序),任何一侧变更必须同步另一侧。", "module": "pbl_runtime_ext", "engine": "mariadb", "charset": "utf8mb4", - "tenant_scoped": true + "collate": "utf8mb4_general_ci", + "tenant_scoped": true, + "primary": ["id", "created_at"], + "append_only": true, + "write_paths": ["INSERT only"], + "guards": { + "append_only": { + "type": "stored_procedure+triggers", + "procedure": "pbl_assert_append_only()", + "triggers": ["BEFORE UPDATE", "BEFORE DELETE"], + "sqlstate": "45000", + "break_glass": "@pbl_guard_ctx", + "note": "sor.U()/sor.D() 会被触发器拒绝;本模块所有写路径只发 INSERT(tx_event/tx_write 已如此)" + } + }, + "partition": { + "method": "RANGE COLUMNS", + "column": "created_at", + "interval": "month", + "prefix": "p", + "max_partition": "pmax", + "precreate_months": 6, + "retention_months": 14, + "note": "PARTITION BY RANGE COLUMNS(`created_at`) (PARTITION pYYYYMM VALUES LESS THAN (DATE 'YYYY-MM-01'), ..., PARTITION pmax VALUES LESS THAN (MAXVALUE))" + }, + "ddl_source": "modules/pbl_runtime_ext/scripts/pbl_runtime_event_ddl.py" } ], "fields": [ - { - "name": "tenant_id", - "comment": "租户ID(强制打头)", - "null": false, - "type": "str", - "length": 32 - }, - { - "name": "id", - "comment": "主键", - "null": false, - "type": "int", - "length": 20, - "unsigned": true, - "auto_increment": true - }, - { - "name": "event_uid", - "comment": "事件UID", - "null": false, - "type": "str", - "length": 32 - }, - { - "name": "session_id", - "comment": "会话", - "null": false, - "type": "bigint" - }, - { - "name": "world_id", - "comment": "世界", - "null": false, - "type": "bigint" - }, - { - "name": "actor_id", - "comment": "触发者", - "null": false, - "type": "str", - "length": 32 - }, - { - "name": "event_type", - "comment": "事件类型", - "null": false, - "type": "str", - "length": 64 - }, - { - "name": "payload_json", - "comment": "事件体", - "null": true, - "type": "json" - }, - { - "name": "causation_id", - "comment": "因果链", - "null": false, - "type": "str", - "length": 32 - }, - { - "name": "state_version", - "comment": "状态版本", - "null": false, - "type": "bigint" - }, - { - "name": "seq", - "comment": "会话内单调序号", - "null": false, - "type": "bigint" - }, - { - "name": "occurred_at", - "comment": "发生时间", - "null": false, - "type": "datetime" - }, - { - "name": "created_at", - "comment": "创建时间", - "null": false, - "type": "datetime" - }, - { - "name": "updated_at", - "comment": "更新时间", - "null": false, - "type": "datetime" - } + {"name": "id", "title": "自增ID", "comment": "自增ID(逻辑主键;物理主键=(id,created_at))", "null": false, "type": "int", "length": 20, "unsigned": true, "auto_increment": true}, + {"name": "tenant_id", "title": "租户ID", "comment": "租户ID(多租户强制打头)", "null": false, "type": "str", "length": 32, "default": ""}, + {"name": "event_uid", "title": "事件UID", "comment": "事件UID(uuid,应用层生成)", "null": false, "type": "str", "length": 64}, + {"name": "event_code", "title": "事件编码", "comment": "事件编码", "null": false, "type": "str", "length": 64, "default": ""}, + {"name": "idem_key", "title": "幂等键", "comment": "幂等键(同键重复投递只落一条)", "null": false, "type": "str", "length": 128, "default": ""}, + {"name": "world_id", "title": "世界ID", "comment": "世界ID(引用 world 基表,只读)", "null": false, "type": "bigint", "default": 0}, + {"name": "scene_id", "title": "场景/会话ID", "comment": "场景/会话ID(引用 scense 基表,只读)", "null": false, "type": "bigint", "default": 0}, + {"name": "session_id", "title": "游戏会话ID", "comment": "游戏会话ID(M11a 语义,与 scene_id 同域)", "null": false, "type": "bigint", "default": 0}, + {"name": "entity_id", "title": "实体ID", "comment": "实体ID(引用 entity 基表,只读)", "null": false, "type": "str", "length": 64, "default": ""}, + {"name": "actor_id", "title": "触发者", "comment": "触发者(服务端会话解析,客户端禁填)", "null": false, "type": "str", "length": 64, "default": ""}, + {"name": "event_type", "title": "事件类型", "comment": "事件类型", "null": false, "type": "str", "length": 64}, + {"name": "payload", "title": "事件负载", "comment": "事件负载JSON(任务书字段)", "null": true, "type": "text"}, + {"name": "payload_json", "title": "事件负载JSON", "comment": "事件负载JSON(M11a 写路径列名,与 payload 同义留宽)", "null": true, "type": "text"}, + {"name": "causation_id", "title": "因果链", "comment": "因果链:引发本事件的事件UID", "null": false, "type": "str", "length": 64, "default": ""}, + {"name": "seq", "title": "会话内单调序号", "comment": "会话内单调序号(轮询游标,应用层生成)", "null": false, "type": "bigint", "default": 0}, + {"name": "seq_no", "title": "会话内单调序号(M11a)", "comment": "会话内单调序号(M11a 写路径列名)", "null": false, "type": "bigint", "default": 0}, + {"name": "source", "title": "来源", "comment": "来源:runtime/agent/script/client_intent", "null": false, "type": "str", "length": 32, "default": "runtime"}, + {"name": "state", "title": "事件状态", "comment": "applied/rejected/rolled_back", "null": false, "type": "str", "length": 16, "default": "applied"}, + {"name": "state_version", "title": "服务端权威版本", "comment": "本事件推进到的服务端权威版本", "null": false, "type": "bigint", "default": 0}, + {"name": "tx_group", "title": "事务组", "comment": "事务组(同组同事务)", "null": false, "type": "str", "length": 64, "default": ""}, + {"name": "broadcast", "title": "是否参与广播", "comment": "是否参与广播 0/1", "null": false, "type": "short", "default": 1}, + {"name": "created_by", "title": "创建人", "comment": "创建人", "null": false, "type": "bigint", "default": 0}, + {"name": "created_at", "title": "创建时间", "comment": "创建时间(分区键,禁TIMESTAMP)", "null": false, "type": "datetime", "default": "CURRENT_TIMESTAMP"}, + {"name": "updated_at", "title": "记录时间戳", "comment": "记录时间戳(append-only:永不 UPDATE)", "null": false, "type": "datetime", "default": "CURRENT_TIMESTAMP"}, + {"name": "occurred_at", "title": "兼容列(旧分区键)", "comment": "兼容列(M11a 旧分区键,新写入可空;不再作为任何唯一键/分区键成员)", "null": true, "type": "datetime"} ], "indexes": [ - { - "name": "uk_re_uid", - "unique": true, - "fields": [ - "tenant_id", - "event_uid", - "occurred_at" - ] - }, - { - "name": "idx_re_session_seq", - "unique": false, - "fields": [ - "tenant_id", - "session_id", - "seq" - ] - }, - { - "name": "PRIMARY", - "unique": true, - "fields": [ - "id" - ] - } + {"name": "PRIMARY", "idxtype": "primary", "unique": true, "fields": ["id", "created_at"], "idxfields": ["id", "created_at"], "comment": "复合主键:分区表唯一键必须包含分区列 created_at"}, + {"name": "uk_event_uid", "idxtype": "unique", "unique": true, "fields": ["tenant_id", "event_uid", "created_at"], "idxfields": ["tenant_id", "event_uid", "created_at"]}, + {"name": "uk_tenant_idem", "idxtype": "unique", "unique": true, "fields": ["tenant_id", "idem_key", "created_at"], "idxfields": ["tenant_id", "idem_key", "created_at"]}, + {"name": "ix_scene_created", "idxtype": "index", "unique": false, "fields": ["scene_id", "created_at"], "idxfields": ["scene_id", "created_at"]}, + {"name": "ix_tenant_session_seq", "idxtype": "index", "unique": false, "fields": ["tenant_id", "session_id", "seq"], "idxfields": ["tenant_id", "session_id", "seq"]}, + {"name": "ix_tenant_session_seqno", "idxtype": "index", "unique": false, "fields": ["tenant_id", "session_id", "seq_no"], "idxfields": ["tenant_id", "session_id", "seq_no"]}, + {"name": "ix_tenant_world_type", "idxtype": "index", "unique": false, "fields": ["tenant_id", "world_id", "event_type"], "idxfields": ["tenant_id", "world_id", "event_type"]}, + {"name": "ix_tx_group", "idxtype": "index", "unique": false, "fields": ["tx_group"], "idxfields": ["tx_group"]}, + {"name": "ix_created_at", "idxtype": "index", "unique": false, "fields": ["created_at"], "idxfields": ["created_at"]} ], "codes": [ - { - "field": "event_type", - "appcode": "pbl_event_type" - } + {"field": "event_type", "appcode": "pbl_event_type"} ] }