From ba4bb51a07910799ec518b7c5df0b1473f2bab65 Mon Sep 17 00:00:00 2001 From: lingniu Date: Wed, 1 Jul 2026 07:37:50 +0800 Subject: [PATCH] refactor: make latest state optional --- DECISIONS.md | 9 +++++++++ README.md | 4 +++- docs/module-data-flow.html | 4 ++-- docs/operations/gb32960-service-split-runbook.md | 2 +- docs/target-architecture.md | 5 +++++ .../ingest/historyapp/MavenModuleProfileTest.java | 13 +++++++++++++ pom.xml | 7 ++++++- 7 files changed, 39 insertions(+), 5 deletions(-) diff --git a/DECISIONS.md b/DECISIONS.md index 24809262..affc2ebb 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -81,3 +81,12 @@ 2. JSATL12 仅保留在 `optional-attachments` profile,需要附件上传能力时显式构建。 3. 默认优化和验证优先覆盖活跃接入链路,附件上传能力保持源码可用但不增加默认构建面。 - **Consequences**: 默认构建更轻,生产部署边界更清晰;附件上传相关测试需要通过 `-Poptional-attachments` 显式运行。 + +## ADR-013 最新状态服务:Optional only +- **Status**: Accepted +- **Context**: Redis 最新状态查询是独立消费能力,但当前默认 Portainer 部署和 Woodpecker 镜像发布只包含三条接入链路、history 和 analytics;`vehicle-state-service` 没有独立 app,也不应增加默认构建面。 +- **Decision**: + 1. `vehicle-state-service` 不进入默认 Maven reactor。 + 2. vehicle-state-service 仅保留在 `optional-latest-state` profile,需要 Redis 最新状态查询能力时显式构建。 + 3. 默认优化和验证优先覆盖活跃接入、TDengine 历史和 MySQL 指标链路。 +- **Consequences**: 默认构建和部署边界继续收窄;最新状态能力保持源码可用,但其测试需要通过 `-Poptional-latest-state` 显式运行。 diff --git a/README.md b/README.md index 046286f8..ff67a362 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ lingniu-vehicle-ingest/ │ │ └── event-file-store/ 可选兼容索引(旧 Parquet/DuckDB 路径) │ ├── services/ │ │ ├── event-history-service/ Kafka 全字段事件消费 + 历史查询/导出 -│ │ ├── vehicle-state-service/ Kafka 全字段事件消费 + Redis 热状态查询 +│ │ ├── vehicle-state-service/ Kafka 全字段事件消费 + Redis 热状态查询(optional-latest-state profile) │ │ └── vehicle-stat-service/ Kafka 全字段事件消费 + 可配置日统计 │ └── apps/ │ ├── command-gateway/ HTTP → 设备下行命令(808 位置/参数/属性/控制/区域删除/报警确认 + 1078 音视频控制) @@ -80,6 +80,8 @@ mvn -pl :jt808-ingest-app -am spring-boot:run JSATL12 附件上传不在默认 Maven reactor 中;需要时使用 `-Poptional-attachments` 构建。 +Redis 最新状态查询不在默认 Maven reactor 中;需要时使用 `-Poptional-latest-state` 构建 `vehicle-state-service`。 + ## 迁移说明 本项目是 `lingniu-vehicle-data-reception` 的 v2 重构,采用 strangler fig 渐进式迁移,旧项目保留只读参考。迁移路径与决策参见 `../REFRACTOR_PLAN.md`。 diff --git a/docs/module-data-flow.html b/docs/module-data-flow.html index 3a68e195..2f5efb97 100644 --- a/docs/module-data-flow.html +++ b/docs/module-data-flow.html @@ -325,7 +325,7 @@ flowchart TB subgraph services["消费服务 modules/services"] history["event-history-service
Kafka event/raw 到 TDengine 历史查询"] - state["vehicle-state-service
Kafka 全字段事件到 Redis 热状态"] + state["vehicle-state-service
可选 Redis 热状态
optional-latest-state"] stat["vehicle-stat-service
Kafka 全字段事件到指标表"] end @@ -614,7 +614,7 @@ flowchart LR modules/services/vehicle-state-service - 消费 Kafka 全字段事件,更新车辆最新状态、位置、安全和最后事件到 Redis;生产消费可使用 tryIngest 和自动装配的 EnvelopeConsumerProcessor 隔离坏 protobuf 和缺快照 Envelope,并把失败记录交给死信出口。 + 消费 Kafka 全字段事件,更新车辆最新状态、位置、安全和最后事件到 Redis;仅通过 optional-latest-state profile 显式构建,不属于默认生产 reactor;生产消费可使用 tryIngest 和自动装配的 EnvelopeConsumerProcessor 隔离坏 protobuf 和缺快照 Envelope,并把失败记录交给死信出口。 Kafka Protobuf Envelope。 vehicle:state:{vin}vehicle:location:{vin}vehicle:safety:{vin}毫秒级热查询氢泄露安全 diff --git a/docs/operations/gb32960-service-split-runbook.md b/docs/operations/gb32960-service-split-runbook.md index 3a239169..a5d04256 100644 --- a/docs/operations/gb32960-service-split-runbook.md +++ b/docs/operations/gb32960-service-split-runbook.md @@ -136,7 +136,7 @@ java --sun-misc-unsafe-memory-access=allow \ -jar modules/apps/vehicle-analytics-app/target/vehicle-analytics-app.jar ``` -`vehicle-analytics-app` is intentionally a metric runtime only. Latest-state APIs belong to `vehicle-state-service` and should be deployed as a separate consumer if that surface is needed. +`vehicle-analytics-app` is intentionally a metric runtime only. Latest-state APIs belong to `vehicle-state-service`, which stays outside the default reactor and should be built with `-Poptional-latest-state` and deployed as a separate consumer if that surface is needed. ## Health Verification diff --git a/docs/target-architecture.md b/docs/target-architecture.md index c1faf46d..a9181609 100644 --- a/docs/target-architecture.md +++ b/docs/target-architecture.md @@ -140,6 +140,9 @@ require a separate Redis mileage state. Module: `vehicle-state-service` +This module is outside the default production reactor. Build it with +`-Poptional-latest-state` when Redis latest-state APIs are explicitly needed. + Responsibilities: - Consume normalized Kafka envelopes. @@ -183,6 +186,8 @@ flowchart LR - Xinda Push is absent from default deployment and history consumer bindings. - JSATL12 is absent from the default Maven reactor and available through `optional-attachments`. +- vehicle-state-service is absent from the default Maven reactor and available + through `optional-latest-state`. - History APIs read from TDengine by default; Parquet/DuckDB is optional compatibility only. - Raw frame queries can return complete parsed JSON through `payloadJson.parsed`. diff --git a/modules/apps/vehicle-history-app/src/test/java/com/lingniu/ingest/historyapp/MavenModuleProfileTest.java b/modules/apps/vehicle-history-app/src/test/java/com/lingniu/ingest/historyapp/MavenModuleProfileTest.java index ae90f29d..d55a8cb1 100644 --- a/modules/apps/vehicle-history-app/src/test/java/com/lingniu/ingest/historyapp/MavenModuleProfileTest.java +++ b/modules/apps/vehicle-history-app/src/test/java/com/lingniu/ingest/historyapp/MavenModuleProfileTest.java @@ -41,6 +41,17 @@ class MavenModuleProfileTest { .containsExactly("modules/protocols/protocol-jsatl12"); } + @Test + void latestStateServiceIsOptionalAndOutsideDefaultProductionReactor() throws Exception { + Document pom = rootPom(); + + assertThat(defaultModules(pom)) + .doesNotContain("modules/services/vehicle-state-service"); + + assertThat(profileModules(pom, "optional-latest-state")) + .containsExactly("modules/services/vehicle-state-service"); + } + @Test void xindaIsLegacyOnlyAndOutsideDefaultProductionReactor() throws Exception { Document pom = rootPom(); @@ -76,6 +87,7 @@ class MavenModuleProfileTest { .contains("Eclipse Paho " + projectProperty(pom, "paho-mqtt.version")) .contains("protocol-jsatl12/ 苏标主动安全报警附件(optional-attachments profile)") .contains("event-file-store/ 可选兼容索引(旧 Parquet/DuckDB 路径)") + .contains("vehicle-state-service/ Kafka 全字段事件消费 + Redis 热状态查询(optional-latest-state profile)") .contains("vehicle-history-app/ TDengine 历史查询 + RAW JSON") .contains("vehicle-analytics-app/ JT808 每日里程指标消费") .doesNotContain("Spring Boot 3.4") @@ -108,6 +120,7 @@ class MavenModuleProfileTest { .contains("GB32960、JT808、Yutong MQTT、vehicle-history-app、vehicle-analytics-app") .contains("Xinda Push 仅保留在 `legacy-xinda` profile") .contains("JSATL12 仅保留在 `optional-attachments` profile") + .contains("vehicle-state-service 仅保留在 `optional-latest-state` profile") .doesNotContain("## ADR-004 信达 Push:保留模块但彻底重写\n- **Status**: Accepted") .doesNotContain("Spring Boot 3.4.x"); } diff --git a/pom.xml b/pom.xml index 2feb3a3e..0ac5f217 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,6 @@ modules/sinks/event-file-store modules/sinks/tdengine-history-store modules/services/event-history-service - modules/services/vehicle-state-service modules/services/vehicle-stat-service modules/protocols/protocol-gb32960 modules/protocols/protocol-jt808 @@ -56,6 +55,12 @@ modules/protocols/protocol-jsatl12 + + optional-latest-state + + modules/services/vehicle-state-service + + legacy-xinda