fix(update): make store migration production-safe
这个提交包含在:
父节点
0910cfab12
当前提交
a86b753508
18
Jenkinsfile
vendored
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
正在加载...
在新工单中引用
屏蔽一个用户