1.0.589.sql 5.0 KB

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