refactor(go): keep protocol realtime snapshots lightweight

This commit is contained in:
lingniu
2026-07-02 21:12:33 +08:00
parent d1e28b9e64
commit 04ca0d15d8
5 changed files with 20 additions and 8 deletions

View File

@@ -82,7 +82,7 @@ Redis 使用 DB 50定位为实时缓存不作为历史事实来源。
| Key 族 | 用途 |
| --- | --- |
| `vehicle:latest:{vehicleKey}` | 跨协议合并后的最新核心字段快照,不重复保存完整 parsed |
| `vehicle:latest:{vehicleKey}:{protocol}` | 单协议最新快照 |
| `vehicle:latest:{vehicleKey}:{protocol}` | 单协议最新轻量快照,保留核心 fields 和时间信息,不重复保存完整 parsed |
| `vehicle:realtime-raw:{protocol}:{vehicleKey}` | 单协议最新完整 parsed 状态,是实时完整协议字段的唯一 Redis 副本 |
| `vehicle:online:{vehicleKey}` | 在线状态和 TTL |
| `vehicle:protocols:{vehicleKey}` | 当前车辆最近出现过的协议集合 |

View File

@@ -587,7 +587,7 @@
<td><strong>Redis</strong></td>
<td><code>vehicle:latest:{vehicle_key}:{protocol}</code></td>
<td>realtime-api Kafka consumer</td>
<td>单协议实时快照</td>
<td>单协议实时轻量快照</td>
<td>区分 32960/808/MQTT 的实时状态</td>
</tr>
<tr>

View File

@@ -21,6 +21,11 @@ type Snapshot struct {
UpdatedAtMS int64 `json:"updated_at_ms"`
}
func (s Snapshot) Lightweight() Snapshot {
s.Parsed = nil
return s
}
type OnlineStatus struct {
VehicleKey string `json:"vehicle_key"`
VIN string `json:"vin"`

View File

@@ -55,13 +55,16 @@ func (r *Repository) Update(ctx context.Context, env envelope.FrameEnvelope) err
if err != nil && !errors.Is(err, redis.Nil) {
return err
}
existingParsed, err := r.GetRealtimeRaw(ctx, vehicleKey, env.Protocol)
if err != nil && !errors.Is(err, redis.Nil) {
return err
}
if existingProtocol.VehicleKey != "" {
protocolSnapshot = existingProtocol
if protocolSnapshot.VIN == "" && vin != "" {
protocolSnapshot.VIN = vin
}
mergeFields(&protocolSnapshot, env.Fields, eventMS)
protocolSnapshot.Parsed = mergeParsedForProtocol(env.Protocol, protocolSnapshot.Parsed, env.Parsed)
if eventMS >= protocolSnapshot.EventTimeMS {
protocolSnapshot.EventTimeMS = eventMS
protocolSnapshot.EventID = env.StableEventID()
@@ -70,7 +73,8 @@ func (r *Repository) Update(ctx context.Context, env envelope.FrameEnvelope) err
}
protocolSnapshot.UpdatedAtMS = nowMS
}
if err := r.setJSON(ctx, protocolKey(vehicleKey, env.Protocol), protocolSnapshot, r.cfg.ttl()); err != nil {
protocolSnapshot.Parsed = mergeParsedForProtocol(env.Protocol, existingParsed, env.Parsed)
if err := r.setJSON(ctx, protocolKey(vehicleKey, env.Protocol), protocolSnapshot.Lightweight(), r.cfg.ttl()); err != nil {
return err
}
if err := r.setJSON(ctx, realtimeRawKey(vehicleKey, env.Protocol), protocolSnapshot.Parsed, r.cfg.ttl()); err != nil {

View File

@@ -67,7 +67,7 @@ func TestRepositoryUpdatesMergedAndProtocolSnapshots(t *testing.T) {
}
}
func TestRepositoryStoresFullParsedProtocolSnapshotAndMergesGB32960Units(t *testing.T) {
func TestRepositoryStoresFullParsedOnlyInRealtimeRawAndMergesGB32960Units(t *testing.T) {
repo, closeFn := newTestRepository(t)
defer closeFn()
ctx := context.Background()
@@ -110,9 +110,12 @@ func TestRepositoryStoresFullParsedProtocolSnapshotAndMergesGB32960Units(t *test
if err != nil {
t.Fatalf("GetRealtimeRaw() error = %v", err)
}
units := protocol.Parsed["data_units"].([]any)
if len(units) != 2 {
t.Fatalf("expected merged gb32960 units, got %#v", protocol.Parsed)
protocolJSON, err := json.Marshal(protocol)
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(protocolJSON), `"parsed"`) {
t.Fatalf("protocol snapshot should not duplicate full parsed data: %s", string(protocolJSON))
}
if len(realtimeRaw["data_units"].([]any)) != 2 {
t.Fatalf("realtime-raw did not keep merged parsed fields: %#v", realtimeRaw)