From ccd196724229f945ca612aa7028dbec3a2b61026 Mon Sep 17 00:00:00 2001 From: zhx Date: Mon, 25 May 2026 19:52:13 +0800 Subject: [PATCH] fix: backfill wallet outbox initdb migrations --- .../mysql/initdb/001_wallet_service.sql | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/services/wallet-service/deploy/mysql/initdb/001_wallet_service.sql b/services/wallet-service/deploy/mysql/initdb/001_wallet_service.sql index cf4e548b..6ec12e53 100644 --- a/services/wallet-service/deploy/mysql/initdb/001_wallet_service.sql +++ b/services/wallet-service/deploy/mysql/initdb/001_wallet_service.sql @@ -78,6 +78,62 @@ CREATE TABLE IF NOT EXISTS wallet_outbox ( KEY idx_wallet_outbox_tx (app_code, transaction_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包事件 outbox 表'; +-- 老环境可能已经存在 wallet_outbox,CREATE TABLE IF NOT EXISTS 不会补齐后续新增的投递锁字段。 +-- 这里用 information_schema 生成幂等 ALTER,保证重复执行 initdb 时不会因重复列名失败。 +SET @ddl := IF( + (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND COLUMN_NAME = 'worker_id') = 0, + 'ALTER TABLE wallet_outbox ADD COLUMN worker_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''MQ 投递 worker ID'' AFTER status', + 'SELECT 1' +); +PREPARE stmt FROM @ddl; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- 投递锁过期时间用于多实例 claim outbox,老库缺这个列时会导致 worker 查询直接 1054。 +SET @ddl := IF( + (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND COLUMN_NAME = 'lock_until_ms') = 0, + 'ALTER TABLE wallet_outbox ADD COLUMN lock_until_ms BIGINT NULL COMMENT ''MQ 投递锁过期时间,UTC epoch ms'' AFTER worker_id', + 'SELECT 1' +); +PREPARE stmt FROM @ddl; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- 下一次重试时间让失败 outbox 可延迟重投;老库缺列时待投递扫描会直接失败。 +SET @ddl := IF( + (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND COLUMN_NAME = 'next_retry_at_ms') = 0, + 'ALTER TABLE wallet_outbox ADD COLUMN next_retry_at_ms BIGINT NULL COMMENT ''下一次 MQ 投递重试时间,UTC epoch ms'' AFTER retry_count', + 'SELECT 1' +); +PREPARE stmt FROM @ddl; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- pending 索引的列顺序跟 outbox 扫描条件绑定;为兼容历史索引,存在就先删除再按当前结构重建。 +SET @ddl := IF( + (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND INDEX_NAME = 'idx_wallet_outbox_pending') > 0, + 'ALTER TABLE wallet_outbox DROP INDEX idx_wallet_outbox_pending', + 'SELECT 1' +); +PREPARE stmt FROM @ddl; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @ddl := 'ALTER TABLE wallet_outbox ADD INDEX idx_wallet_outbox_pending (app_code, status, next_retry_at_ms, created_at_ms)'; +PREPARE stmt FROM @ddl; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- claim 索引用于查找锁过期的消息;仅在缺失时添加,避免重复执行 initdb 报重复索引。 +SET @ddl := IF( + (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND INDEX_NAME = 'idx_wallet_outbox_claim') = 0, + 'ALTER TABLE wallet_outbox ADD INDEX idx_wallet_outbox_claim (app_code, status, lock_until_ms, created_at_ms)', + 'SELECT 1' +); +PREPARE stmt FROM @ddl; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + CREATE TABLE IF NOT EXISTS wallet_gift_prices ( app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码,用于多租户隔离', gift_id VARCHAR(96) NOT NULL COMMENT '礼物 ID',