fix: fence command events by dispatch generation

This commit is contained in:
2026-09-06 09:18:37 +00:00
parent 981cd441fd
commit 94c3f6dcb4
3 changed files with 23 additions and 18 deletions
+3 -3
View File
@@ -244,7 +244,7 @@ func (server *AgentServer) serveConnection(parent context.Context, connection *w
continue continue
} }
if event := envelope.GetCommandEvent(); event != nil { if event := envelope.GetCommandEvent(); event != nil {
appendEvent, eventErr := eventAppendFromWire(event, hello.GetClientId(), server.now()) appendEvent, eventErr := eventAppendFromWire(event, hello.GetClientId(), registration.Generation, server.now())
if eventErr != nil { if eventErr != nil {
server.close(connection, websocket.StatusPolicyViolation, "invalid command event") server.close(connection, websocket.StatusPolicyViolation, "invalid command event")
return return
@@ -263,7 +263,7 @@ func (server *AgentServer) serveConnection(parent context.Context, connection *w
} }
} }
func eventAppendFromWire(event *rvboxv1.CommandEvent, clientID string, receipt time.Time) (store.EventAppend, error) { func eventAppendFromWire(event *rvboxv1.CommandEvent, clientID string, generation uint64, receipt time.Time) (store.EventAppend, error) {
issue, err := domain.ParseUUIDv7(event.GetIssueUuid()) issue, err := domain.ParseUUIDv7(event.GetIssueUuid())
if err != nil { if err != nil {
return store.EventAppend{}, err return store.EventAppend{}, err
@@ -274,7 +274,7 @@ func eventAppendFromWire(event *rvboxv1.CommandEvent, clientID string, receipt t
} }
var immutable [32]byte var immutable [32]byte
copy(immutable[:], event.GetImmutableEventSha256()) copy(immutable[:], event.GetImmutableEventSha256())
result := store.EventAppend{IssueUUID: [16]byte(issue), ClientID: clientID, EventSeq: event.GetEventSeq(), ObservedUnixNano: event.GetObservedAt().AsTime().UnixNano(), ReceiptUnixNano: receipt.UnixNano(), EventType: eventType(event), Compression: 1, RawLength: uint64(len(payload)), Payload: payload, ImmutableSHA256: immutable} result := store.EventAppend{IssueUUID: [16]byte(issue), ClientID: clientID, SessionGeneration: generation, EventSeq: event.GetEventSeq(), ObservedUnixNano: event.GetObservedAt().AsTime().UnixNano(), ReceiptUnixNano: receipt.UnixNano(), EventType: eventType(event), Compression: 1, RawLength: uint64(len(payload)), Payload: payload, ImmutableSHA256: immutable}
if output := event.GetOutput(); output != nil { if output := event.GetOutput(); output != nil {
result.Stream = uint16(output.GetStream()) result.Stream = uint16(output.GetStream())
result.Output = true result.Output = true
+2 -2
View File
@@ -116,8 +116,8 @@ func TestWireEventAppendCarriesClientBinding_HP_EVENT_01(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
event.ImmutableEventSha256 = digest[:] event.ImmutableEventSha256 = digest[:]
appendEvent, err := eventAppendFromWire(event, "client-a", time.Now()) appendEvent, err := eventAppendFromWire(event, "client-a", 7, time.Now())
if err != nil || appendEvent.ClientID != "client-a" || appendEvent.EventSeq != 1 || appendEvent.EventType != 4 || appendEvent.ImmutableSHA256 != digest { if err != nil || appendEvent.ClientID != "client-a" || appendEvent.SessionGeneration != 7 || appendEvent.EventSeq != 1 || appendEvent.EventType != 4 || appendEvent.ImmutableSHA256 != digest {
t.Fatalf("wire event append = %#v, %v", appendEvent, err) t.Fatalf("wire event append = %#v, %v", appendEvent, err)
} }
} }
+18 -13
View File
@@ -32,19 +32,20 @@ type FaultInjectorFunc func(name string) error
func (function FaultInjectorFunc) Checkpoint(name string) error { return function(name) } func (function FaultInjectorFunc) Checkpoint(name string) error { return function(name) }
type EventAppend struct { type EventAppend struct {
IssueUUID [16]byte IssueUUID [16]byte
ClientID string ClientID string
EventSeq uint64 SessionGeneration uint64
ObservedUnixNano int64 EventSeq uint64
ReceiptUnixNano int64 ObservedUnixNano int64
EventType uint16 ReceiptUnixNano int64
Stream uint16 EventType uint16
Compression uint16 Stream uint16
RawLength uint64 Compression uint16
Payload []byte RawLength uint64
ImmutableSHA256 [32]byte Payload []byte
Output bool ImmutableSHA256 [32]byte
UseCloseout bool Output bool
UseCloseout bool
} }
type EventAppendResult struct { type EventAppendResult struct {
@@ -91,6 +92,10 @@ JOIN storage_counters ON storage_counters.singleton = 1 WHERE commands.issue_uui
query += ` AND commands.client_id = ?` query += ` AND commands.client_id = ?`
arguments = append(arguments, event.ClientID) arguments = append(arguments, event.ClientID)
} }
if event.SessionGeneration != 0 {
query += ` AND commands.target_session_generation = ?`
arguments = append(arguments, event.SessionGeneration)
}
err = database.QueryRowContext(ctx, query, arguments...).Scan( err = database.QueryRowContext(ctx, query, arguments...).Scan(
&lastSequence, &commandOutputCharged, &commandCharged, &closeoutRemaining, &clientID, &clientCharged, &serverCharged) &lastSequence, &commandOutputCharged, &commandCharged, &closeoutRemaining, &clientID, &clientCharged, &serverCharged)
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {