feat: add durable Worker execution and WSS server

This commit is contained in:
2026-09-17 08:22:24 +08:00
parent 9701b7a071
commit cd0dc7011b
31 changed files with 3007 additions and 16 deletions

View File

@@ -0,0 +1,62 @@
-- Worker 会话隔离和迟到结果证据。P2 之前没有受支持的 Worker 注册接口。
ALTER TABLE pulse_worker_sessions ADD UNIQUE KEY uq_session_instance_id(namespace_id, worker_instance_id, id);
CREATE TABLE pulse_worker_instances (
namespace_id BINARY(16) NOT NULL COMMENT '进程所属命名空间,参与授权和所有关联',
id BINARY(16) NOT NULL COMMENT 'Worker 进程实例标识,进程重启必须换新值',
revision BIGINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '持久化变更版本,从一开始递增',
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '首次注册时间,UTC 微秒精度',
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '最近变更时间,不替代会话代次',
credential_id BINARY(16) NOT NULL COMMENT '初始注册凭据,进程生命周期内固定',
queue_id BINARY(16) NOT NULL COMMENT '绑定队列,切换队列需创建新进程实例',
secret_digest BINARY(32) NOT NULL COMMENT '随机进程恢复秘密的 SHA-256 摘要,不保存原文',
registration_digest BINARY(32) NOT NULL COMMENT '队列及处理器版本集合的语义摘要,重连必须匹配',
session_epoch BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '最大已分配连接代次,注册前为零',
current_session_id BINARY(16) NULL COMMENT '当前会话,注册事务建立会话前为空',
draining BOOLEAN NOT NULL DEFAULT FALSE COMMENT '持久化排空标记,重连不能清除',
PRIMARY KEY(namespace_id,id),
UNIQUE KEY uq_worker_credential(namespace_id,id,credential_id),
CONSTRAINT ck_worker_instance_revision CHECK (revision>0),
CONSTRAINT ck_worker_instance_session CHECK ((session_epoch=0 AND current_session_id IS NULL) OR (session_epoch>0 AND current_session_id IS NOT NULL)),
CONSTRAINT fk_worker_instance_credential FOREIGN KEY(namespace_id,credential_id) REFERENCES orbit_credentials(namespace_id,id) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT fk_worker_instance_queue FOREIGN KEY(namespace_id,queue_id) REFERENCES pulse_queues(namespace_id,id) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT fk_worker_instance_session FOREIGN KEY(namespace_id,id,current_session_id) REFERENCES pulse_worker_sessions(namespace_id,worker_instance_id,id) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_as_cs COMMENT='Worker 进程恢复身份和当前会话头,用于跨节点隔离旧连接';
ALTER TABLE pulse_worker_sessions ADD CONSTRAINT fk_worker_session_instance FOREIGN KEY(namespace_id,worker_instance_id,credential_id) REFERENCES pulse_worker_instances(namespace_id,id,credential_id) ON DELETE RESTRICT ON UPDATE RESTRICT;
ALTER TABLE pulse_worker_sessions ADD CONSTRAINT ck_worker_session_capacity CHECK (capacity<=256);
ALTER TABLE pulse_attempts ADD KEY ix_attempt_session_state(namespace_id,session_id,state);
ALTER TABLE pulse_attempts ADD CONSTRAINT ck_attempt_lifecycle CHECK ((state IN ('LEASED','RUNNING') AND ended_at IS NULL) OR (state NOT IN ('LEASED','RUNNING') AND ended_at IS NOT NULL));
ALTER TABLE pulse_attempts ADD CONSTRAINT ck_attempt_start CHECK ((state='LEASED' AND authorized_at IS NULL) OR (state='RUNNING' AND authorized_at IS NOT NULL) OR state NOT IN ('LEASED','RUNNING'));
ALTER TABLE pulse_tasks ADD KEY ix_task_deadline(state,deadline_at,namespace_id,id);
ALTER TABLE pulse_tasks ADD KEY ix_task_start_deadline(state,start_deadline_at,namespace_id,id);
CREATE TABLE pulse_attempt_evidence (
namespace_id BINARY(16) NOT NULL COMMENT '证据所属命名空间,与尝试一致',
id BINARY(16) NOT NULL COMMENT '证据记录标识',
revision BIGINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '记录版本;证据追加保存,不覆盖',
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '首次收到证据的数据库时间,UTC',
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '写入时间,追加记录与创建时间相同',
attempt_id BINARY(16) NOT NULL COMMENT '证据所属执行尝试',
message_id BINARY(16) NOT NULL COMMENT '结果消息身份,重报保持不变',
outcome VARCHAR(16) NOT NULL COMMENT 'Worker 声明的结果:SUCCEEDED、FAILED 或 UNKNOWN',
error_code VARCHAR(64) NULL COMMENT '稳定错误分类;无错误时为空,不保存原始异常正文',
payload MEDIUMTEXT NOT NULL COMMENT '结果或证据引用的 JSON 文本,保留精确数字',
request_digest BINARY(32) NOT NULL COMMENT '结果语义摘要,排除会话与秘密',
reason VARCHAR(32) NOT NULL COMMENT '证据未改写权威结果的原因:LEASE_LOST、NOT_STARTED 或 RESULT_CONFLICT',
PRIMARY KEY(namespace_id,id),
UNIQUE KEY uq_attempt_evidence_message(namespace_id,attempt_id,message_id),
CONSTRAINT ck_attempt_evidence_revision CHECK(revision>0),
CONSTRAINT ck_attempt_evidence_json CHECK(JSON_VALID(payload)),
CONSTRAINT ck_attempt_evidence_outcome CHECK(outcome IN ('SUCCEEDED','FAILED','UNKNOWN')),
CONSTRAINT ck_attempt_evidence_reason CHECK(reason IN ('LEASE_LOST','NOT_STARTED','RESULT_CONFLICT')),
CONSTRAINT fk_attempt_evidence_attempt FOREIGN KEY(namespace_id,attempt_id) REFERENCES pulse_attempts(namespace_id,id) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_as_cs COMMENT='迟到与冲突结果的追加证据,不自动改变任务终态';
CREATE TRIGGER immutable_attempt_evidence BEFORE UPDATE ON pulse_attempt_evidence FOR EACH ROW SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='attempt evidence is immutable';