refactor(go): keep protocol realtime snapshots lightweight
This commit is contained in:
@@ -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}` | 当前车辆最近出现过的协议集合 |
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user