fix(update): make store migration production-safe

这个提交包含在:
XuqmGroup 2026-07-28 21:50:28 +08:00
父节点 0910cfab12
当前提交 a86b753508
共有 3 个文件被更改,包括 68 次插入9 次删除

18
Jenkinsfile vendored
查看文件

@ -165,6 +165,24 @@ pipeline {
ssh -i "%SSH_KEY%" -o StrictHostKeyChecking=no ${PROD_USER}@${PROD_HOST} "docker image prune -f 2>/dev/null || true; docker pull ${latestImage} || exit 1; docker compose -f ${COMPOSE_FILE} up -d --no-deps --force-recreate ${svc} || exit 1; docker image prune -f" ssh -i "%SSH_KEY%" -o StrictHostKeyChecking=no ${PROD_USER}@${PROD_HOST} "docker image prune -f 2>/dev/null || true; docker pull ${latestImage} || exit 1; docker compose -f ${COMPOSE_FILE} up -d --no-deps --force-recreate ${svc} || exit 1; docker image prune -f"
""" """
} }
// Jenkins 不能仅以 docker compose 返回 0 判定部署成功。Spring 服务可能
// 在容器启动后因配置或数据库迁移失败进入重启循环,必须等待真实健康端点。
def healthPortByService = [
'tenant-service': 9001,
'update-service': 8084,
'xuqm-bugcollect-service': 9006,
]
def healthPort = healthPortByService[svc]
if (healthPort != null) {
retry(20) {
sleep time: 3, unit: 'SECONDS'
bat """
chcp 65001 >nul
ssh -i "%SSH_KEY%" -o StrictHostKeyChecking=no ${PROD_USER}@${PROD_HOST} "curl -fsS http://127.0.0.1:${healthPort}/actuator/health | grep -q '\\\"status\\\":\\\"UP\\\"'"
"""
}
}
} }
// 合并更新 versions.json只改动本次构建涉及的服务,不覆盖其它服务或 web 条目) // 合并更新 versions.json只改动本次构建涉及的服务,不覆盖其它服务或 web 条目)

查看文件

@ -21,7 +21,7 @@ CREATE TABLE update_store_application (
updated_at DATETIME(6) NOT NULL, updated_at DATETIME(6) NOT NULL,
UNIQUE KEY uk_store_application (app_key, store_type), UNIQUE KEY uk_store_application (app_key, store_type),
INDEX idx_store_application_sync (enabled, last_synced_at) INDEX idx_store_application_sync (enabled, last_synced_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE update_store_credential_profile ( CREATE TABLE update_store_credential_profile (
id VARCHAR(64) NOT NULL PRIMARY KEY, id VARCHAR(64) NOT NULL PRIMARY KEY,
@ -37,7 +37,7 @@ CREATE TABLE update_store_credential_profile (
created_at DATETIME(6) NOT NULL, created_at DATETIME(6) NOT NULL,
updated_at DATETIME(6) NOT NULL, updated_at DATETIME(6) NOT NULL,
UNIQUE KEY uk_store_credential_purpose (app_key, store_type, purpose) UNIQUE KEY uk_store_credential_purpose (app_key, store_type, purpose)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE update_store_secret ( CREATE TABLE update_store_secret (
secret_ref VARCHAR(256) NOT NULL PRIMARY KEY, secret_ref VARCHAR(256) NOT NULL PRIMARY KEY,
@ -46,7 +46,7 @@ CREATE TABLE update_store_secret (
key_version VARCHAR(32) NOT NULL, key_version VARCHAR(32) NOT NULL,
created_at DATETIME(6) NOT NULL, created_at DATETIME(6) NOT NULL,
updated_at DATETIME(6) NOT NULL updated_at DATETIME(6) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE update_store_version ( CREATE TABLE update_store_version (
id VARCHAR(64) NOT NULL PRIMARY KEY, id VARCHAR(64) NOT NULL PRIMARY KEY,
@ -67,7 +67,7 @@ CREATE TABLE update_store_version (
CONSTRAINT fk_store_version_application CONSTRAINT fk_store_version_application
FOREIGN KEY (store_application_id) REFERENCES update_store_application(id) FOREIGN KEY (store_application_id) REFERENCES update_store_application(id)
ON DELETE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE update_store_region_availability ( CREATE TABLE update_store_region_availability (
id VARCHAR(64) NOT NULL PRIMARY KEY, id VARCHAR(64) NOT NULL PRIMARY KEY,
@ -80,7 +80,7 @@ CREATE TABLE update_store_region_availability (
CONSTRAINT fk_store_region_version CONSTRAINT fk_store_region_version
FOREIGN KEY (store_version_id) REFERENCES update_store_version(id) FOREIGN KEY (store_version_id) REFERENCES update_store_version(id)
ON DELETE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE update_store_state_event ( CREATE TABLE update_store_state_event (
id VARCHAR(64) NOT NULL PRIMARY KEY, id VARCHAR(64) NOT NULL PRIMARY KEY,
@ -104,7 +104,7 @@ CREATE TABLE update_store_state_event (
CONSTRAINT fk_store_event_version CONSTRAINT fk_store_event_version
FOREIGN KEY (store_version_id) REFERENCES update_store_version(id) FOREIGN KEY (store_version_id) REFERENCES update_store_version(id)
ON DELETE SET NULL ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE update_store_update_link ( CREATE TABLE update_store_update_link (
id VARCHAR(64) NOT NULL PRIMARY KEY, id VARCHAR(64) NOT NULL PRIMARY KEY,
@ -120,7 +120,7 @@ CREATE TABLE update_store_update_link (
CONSTRAINT fk_store_link_app_version CONSTRAINT fk_store_link_app_version
FOREIGN KEY (app_version_id) REFERENCES update_app_version(id) FOREIGN KEY (app_version_id) REFERENCES update_app_version(id)
ON DELETE RESTRICT ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE update_store_notification_policy ( CREATE TABLE update_store_notification_policy (
id VARCHAR(64) NOT NULL PRIMARY KEY, id VARCHAR(64) NOT NULL PRIMARY KEY,
@ -134,7 +134,7 @@ CREATE TABLE update_store_notification_policy (
created_at DATETIME(6) NOT NULL, created_at DATETIME(6) NOT NULL,
updated_at DATETIME(6) NOT NULL, updated_at DATETIME(6) NOT NULL,
UNIQUE KEY uk_store_notification_policy (app_key) UNIQUE KEY uk_store_notification_policy (app_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE update_store_notification_outbox ( CREATE TABLE update_store_notification_outbox (
id VARCHAR(64) NOT NULL PRIMARY KEY, id VARCHAR(64) NOT NULL PRIMARY KEY,
@ -152,4 +152,4 @@ CREATE TABLE update_store_notification_outbox (
CONSTRAINT fk_store_notification_event CONSTRAINT fk_store_notification_event
FOREIGN KEY (store_event_id) REFERENCES update_store_state_event(id) FOREIGN KEY (store_event_id) REFERENCES update_store_state_event(id)
ON DELETE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

查看文件

@ -0,0 +1,41 @@
package com.xuqm.update.config;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;
class MigrationSchemaContractTest {
@Test
void storeMonitoringTablesUseLegacyCompatibleCollation() throws IOException {
var resource = getClass().getResourceAsStream(
"/db/migration/V5__store_monitoring_domain.sql"
);
assertTrue(resource != null, "V5 migration must be packaged");
String sql;
try (resource) {
sql = new String(resource.readAllBytes(), StandardCharsets.UTF_8);
}
assertEquals(9, occurrences(sql, "CREATE TABLE update_store_"));
assertEquals(
9,
occurrences(sql, "DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"),
"Every V5 table must match the collation of existing varchar foreign keys"
);
}
private static int occurrences(String value, String token) {
int count = 0;
int offset = 0;
while ((offset = value.indexOf(token, offset)) >= 0) {
count++;
offset += token.length();
}
return count;
}
}