From 8ada1e571435b9235db081b4bd0b8ee1e6c4126b Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Tue, 4 Aug 2026 09:11:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8D=95=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E8=A2=ABMQ=E9=85=8D=E7=BD=AE=E9=98=BB?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/docker-compose.yml | 6 +-- deploy/scripts/deploy-services.sh | 42 +++++++++++++++++++ docs/公共导出与下载中心接入说明.md | 2 +- docs/公共导出中心RocketMQ架构设计.md | 2 +- .../ExportInfrastructureContractTest.java | 8 +++- 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index e7a116f12..46dd39d9a 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -125,9 +125,9 @@ services: FILE_DB_PASSWORD: ${FILE_DB_PASSWORD} FILE_STORAGE_ROOT: /data/files JAVA_TOOL_OPTIONS: "-Xms1g -Xmx2g -XX:+ExitOnOutOfMemoryError -Dfile.encoding=UTF-8" - ROCKETMQ_NAME_SERVER: ${ROCKETMQ_NAME_SERVER} - # 必须显式设置:测试填 test-,生产填空字符串;使用 ? 而不是 :?,允许生产空值。 - MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX?MQ_TOPIC_PREFIX must be set; use test- for test and an empty value for production} + # Compose 会插值整份文件,即使只部署 auth 等其他服务;File 的必填校验由 deploy-services.sh 按服务执行。 + ROCKETMQ_NAME_SERVER: ${ROCKETMQ_NAME_SERVER-} + MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX-} FILE_EXPORT_CONSUMER_ENABLED: ${FILE_EXPORT_CONSUMER_ENABLED:-false} FILE_EXPORT_CONSUMER_CONCURRENCY: ${FILE_EXPORT_CONSUMER_CONCURRENCY:-4} FILE_EXPORT_PUBLISHER_ENABLED: ${FILE_EXPORT_PUBLISHER_ENABLED:-false} diff --git a/deploy/scripts/deploy-services.sh b/deploy/scripts/deploy-services.sh index 4271e1434..9ab70dcf2 100644 --- a/deploy/scripts/deploy-services.sh +++ b/deploy/scripts/deploy-services.sh @@ -19,6 +19,48 @@ fi SERVICES=$(printf '%s' "$SERVICE_CSV" | tr ',' ' ') +env_file_has_key() { + grep -q "^$1=" "$ENV_FILE" +} + +env_file_value() { + sed -n "s/^$1=//p" "$ENV_FILE" | tail -n 1 | tr -d '\r' +} + +case " $SERVICES " in + *" file "*) + if ! env_file_has_key ROCKETMQ_NAME_SERVER || [ -z "$(env_file_value ROCKETMQ_NAME_SERVER)" ]; then + echo "部署 file 服务时,环境文件必须包含非空 ROCKETMQ_NAME_SERVER" >&2 + exit 2 + fi + if ! env_file_has_key MQ_TOPIC_PREFIX; then + echo "部署 file 服务时,环境文件必须显式包含 MQ_TOPIC_PREFIX:测试填 test-,生产填空字符串" >&2 + exit 2 + fi + MQ_PREFIX=$(env_file_value MQ_TOPIC_PREFIX) + case "$DEPLOY_ENV" in + test) + if [ "$MQ_PREFIX" != "test-" ]; then + echo "测试环境部署 file 服务时 MQ_TOPIC_PREFIX 必须为 test-" >&2 + exit 2 + fi + ;; + production) + if [ -n "$MQ_PREFIX" ]; then + echo "生产环境部署 file 服务时 MQ_TOPIC_PREFIX 必须显式为空字符串" >&2 + exit 2 + fi + ;; + *) + if [ -z "$MQ_PREFIX" ] || [ "$MQ_PREFIX" = "test-" ]; then + echo "预发布环境部署 file 服务时 MQ_TOPIC_PREFIX 必须为非空且不能使用 test-" >&2 + exit 2 + fi + ;; + esac + ;; +esac + export DEPLOY_ENV IMAGE_REPOSITORY IMAGE_TAG PULL_POLICY_ARGS="" diff --git a/docs/公共导出与下载中心接入说明.md b/docs/公共导出与下载中心接入说明.md index 23b135cac..ba2bb0510 100644 --- a/docs/公共导出与下载中心接入说明.md +++ b/docs/公共导出与下载中心接入说明.md @@ -100,7 +100,7 @@ FILE_EXPORT_RETENTION_DAYS FILE_STORAGE_ROOT ``` -`MQ_TOPIC_PREFIX` 是部署必填项但允许空值:测试环境显式填 `test-`,生产环境显式填空字符串。不能使用 `:-test-` 作为 Compose 默认值,否则生产空值会被重新替换成测试前缀。 +`MQ_TOPIC_PREFIX` 是 File 部署必填项但允许生产空值:测试环境显式填 `test-`,生产环境显式填空字符串。Compose 单服务部署会插值整份文件,因此 File 服务块本身使用空默认值,避免 Auth/IAM 等无关服务被 MQ 配置阻断;`deploy-services.sh` 只在部署 File 时按环境强校验该变量与 `ROCKETMQ_NAME_SERVER`。 当前 RocketMQ Compose 不映射 Broker 宿主机端口,File 与 Broker 必须同在 `infra-network`,因此 `ROCKETMQ_BROKER_IP` 填 `rocketmq-broker`。Topic 初始化会等待 `BaiyueCluster` 真正注册,任一幂等初始化命令失败后自动重试。 diff --git a/docs/公共导出中心RocketMQ架构设计.md b/docs/公共导出中心RocketMQ架构设计.md index 1bf2181b5..9d2476996 100644 --- a/docs/公共导出中心RocketMQ架构设计.md +++ b/docs/公共导出中心RocketMQ架构设计.md @@ -1258,7 +1258,7 @@ RocketMQ NameServer/Broker 就绪 -> Admin 验收 ``` -环境变量需在 `deploy/docker-compose.yml` 与 Jenkins 中透传:`ROCKETMQ_NAME_SERVER`、`MQ_TOPIC_PREFIX`、`ROCKETMQ_BROKER_IP`、`FILE_EXPORT_CONSUMER_ENABLED`、`FILE_EXPORT_CONSUMER_CONCURRENCY`、`FILE_EXPORT_PUBLISHER_ENABLED`、`FILE_EXPORT_RECONCILER_ENABLED`。`MQ_TOPIC_PREFIX` 不得省略:测试显式设为 `test-`,生产显式设为空字符串。测试与生产的 `FILE_EXPORT_CONSUMER_CONCURRENCY` 初始值均显式设为 `4`,不只依赖应用默认值;三个启用开关首次上线均显式设为 `false`,再按本节顺序逐项改为 `true`。File 容器需要 `HOSTNAME` 可用(Docker 默认提供)。 +环境变量需在 `deploy/docker-compose.yml` 与 Jenkins 中透传:`ROCKETMQ_NAME_SERVER`、`MQ_TOPIC_PREFIX`、`ROCKETMQ_BROKER_IP`、`FILE_EXPORT_CONSUMER_ENABLED`、`FILE_EXPORT_CONSUMER_CONCURRENCY`、`FILE_EXPORT_PUBLISHER_ENABLED`、`FILE_EXPORT_RECONCILER_ENABLED`。Compose 会在单服务部署前插值整份文件,因此不能在 File 服务块使用 `${MQ_TOPIC_PREFIX?...}` 阻断 Auth/IAM 等无关服务;`deploy/scripts/deploy-services.sh` 只在部署 File 时执行环境级强校验。`MQ_TOPIC_PREFIX` 对 File 不得省略:测试必须显式设为 `test-`,生产必须显式设为空字符串。测试与生产的 `FILE_EXPORT_CONSUMER_CONCURRENCY` 初始值均显式设为 `4`,不只依赖应用默认值;三个启用开关首次上线均显式设为 `false`,再按本节顺序逐项改为 `true`。File 容器需要 `HOSTNAME` 可用(Docker 默认提供)。 ## 19. 测试与验收门槛 diff --git a/file/src/test/java/com/baiyue/file/config/ExportInfrastructureContractTest.java b/file/src/test/java/com/baiyue/file/config/ExportInfrastructureContractTest.java index fb408ae0a..333f3e4ca 100644 --- a/file/src/test/java/com/baiyue/file/config/ExportInfrastructureContractTest.java +++ b/file/src/test/java/com/baiyue/file/config/ExportInfrastructureContractTest.java @@ -16,8 +16,12 @@ class ExportInfrastructureContractTest { assertTrue(compose.contains("FILE_EXPORT_PUBLISHER_ENABLED: ${FILE_EXPORT_PUBLISHER_ENABLED:-false}")); assertTrue(compose.contains("FILE_EXPORT_RECONCILER_ENABLED: ${FILE_EXPORT_RECONCILER_ENABLED:-false}")); assertTrue(compose.contains("-Xms1g -Xmx2g")); - assertTrue(compose.contains("MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX?")); - assertTrue(!compose.contains("MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX:-test-}")); + assertTrue(compose.contains("MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX-}")); + assertTrue(compose.contains("ROCKETMQ_NAME_SERVER: ${ROCKETMQ_NAME_SERVER-}")); + String deployScript=read("..","deploy","scripts","deploy-services.sh"); + assertTrue(deployScript.contains("部署 file 服务时,环境文件必须显式包含 MQ_TOPIC_PREFIX")); + assertTrue(deployScript.contains("测试环境部署 file 服务时 MQ_TOPIC_PREFIX 必须为 test-")); + assertTrue(deployScript.contains("环境文件必须包含非空 ROCKETMQ_NAME_SERVER")); } @Test void rocketMqBootstrapCreatesBothGroupsAndAReadableWorkerDlq() throws Exception {