| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- -- 1.0.589 —— ETL 执行机指派改按「部署槽位」,使指派能跨进程重启存活。
- --
- -- 背景(根因):指派原来存在 ado_etl_instance.is_runner,而 instance_id 是
- -- 「机器名:进程ID:启动时间」(AidopInstanceIdentity,进程级唯一是刻意的),
- -- 于是「角色」被绑死在一次进程化身上——执行机每重启一次,指派必然留在一行死记录上,
- -- 全库变成零台存活执行机,定时 ETL 静默停摆。
- -- 2026-09-28 实测:03:40 扇出 28 条 AUTO_NIGHTLY 的实例(ERICGUO:69756,1.0.583)
- -- 04:10 退出,此后没有任何实例能领这批任务(ClaimNextQueuedAsync 对非执行机
- -- 只放行 MANUAL),S5/S6/S7 的队列被永久孤立。
- --
- -- 修法:角色是部署槽位的属性,不是进程化身的属性。
- -- ① 新建 ado_etl_runner_designation —— 指派独立成表,主键固定为 1,
- -- 「最多一台执行机」由结构保证,不再靠写入侧事务先清后置。
- -- ② ado_etl_instance 加 slot_code —— 进程声明自己属于哪个槽位(AIDOP_ETL_SLOT)。
- -- 执行机判定 = 本进程槽位 == 被指派槽位;未声明槽位者永不是执行机(比旧模型更严)。
- -- ③ is_runner 保留为遗留列,运行期代码不再读写;待全部实例升级后单独发版删除。
- --
- -- 注意这不是退回 2026-09-25 之前的配置模型:配置只声明**身份**(我是哪个槽位),
- -- 唯一**权威**仍是本表那条指派记录,页面仍可热切换、无需重启。
- --
- -- 幂等:建表用 IF NOT EXISTS,加列前查 information_schema,回填带 NOT EXISTS 守卫。
- -- ① 指派表
- CREATE TABLE IF NOT EXISTS ado_etl_runner_designation (
- id BIGINT NOT NULL PRIMARY KEY COMMENT '固定为 1:全表只有一行,指派唯一性由主键保证',
- slot_code VARCHAR(128) NULL COMMENT '被指派的部署槽位;NULL=无指派(此时无人跑定时 ETL,是允许的状态)',
- assigned_by VARCHAR(64) NULL COMMENT '操作人账号,仅供审计',
- assigned_at DATETIME NULL,
- remark VARCHAR(512) NULL,
- create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
- ) COMMENT 'ETL执行机指派(单行)';
- -- ② 实例表加槽位列
- SET @sql := IF((SELECT COUNT(*) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ado_etl_instance' AND COLUMN_NAME='slot_code')=0,
- 'ALTER TABLE ado_etl_instance ADD COLUMN slot_code VARCHAR(128) NULL COMMENT ''本进程声明所属的部署槽位;NULL=未声明,永不是执行机'' AFTER app_version',
- 'DO 0');
- PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
- SET @sql := IF((SELECT COUNT(*) FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ado_etl_instance' AND INDEX_NAME='idx_etl_instance_slot')=0,
- 'ALTER TABLE ado_etl_instance ADD INDEX idx_etl_instance_slot (slot_code, last_heartbeat_at)',
- 'DO 0');
- PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
- -- ③ 现有实例行按机器名补槽位。
- -- 机器名是该行天然稳定的部分,用它当默认槽位码,升级后同机重启即可继承指派。
- UPDATE ado_etl_instance
- SET slot_code = LOWER(machine_name)
- WHERE slot_code IS NULL
- AND IFNULL(machine_name,'') <> '';
- -- ④ 把现有指派带过来,使升级前后 ETL 连续(决策 D1)。
- -- 取 is_runner=1 那行的机器名作为初始槽位。
- -- 当前库里这一行是开发机 ERICGUO —— 与升级前的实际状态一致,不是新增风险;
- -- 上线正式执行机后请在 MDP 运行监控页改指派到对应槽位。
- -- NOT EXISTS 守卫保证重跑不会覆盖运维之后手工改过的指派。
- INSERT INTO ado_etl_runner_designation (id, slot_code, assigned_by, assigned_at, remark, create_time, update_time)
- SELECT 1,
- LOWER(i.machine_name),
- 'migration-1.0.589',
- NOW(),
- CONCAT('由 1.0.589 从 ado_etl_instance.is_runner=1 迁移(原 instance_id=', i.instance_id, ')'),
- NOW(),
- NOW()
- FROM ado_etl_instance i
- WHERE i.is_runner = 1
- AND IFNULL(i.machine_name,'') <> ''
- AND NOT EXISTS (SELECT 1 FROM ado_etl_runner_designation d WHERE d.id = 1)
- ORDER BY i.last_heartbeat_at DESC
- LIMIT 1;
- -- ⑤ 收口本次事故遗留的孤立队列。
- -- 这批 AUTO_NIGHTLY 已无消费者且一直挡着同 scope 的后续入队;
- -- 夜间作业从本版起会在扇出前自清,故这里只需处理历史存量。
- -- 只碰 QUEUED 且无 requested_by 的行:RUNNING 与页面手工任务一律不动。
- UPDATE ado_module_dashboard_rebuild_job
- SET status = 'CANCELLED',
- current_stage = 'CANCELLED',
- finished_at = NOW(),
- error_message = '执行机指派随进程重启失效导致长期无人领取,由 1.0.589 统一收口',
- update_time = NOW()
- WHERE status = 'QUEUED'
- AND trigger_type = 'AUTO_NIGHTLY'
- AND requested_by IS NULL
- AND submitted_at < DATE_SUB(NOW(), INTERVAL 2 HOUR);
|