MxGateway adapter: ReplayGap sentinel (worker_sequence 0) resets the resume cursor to 0 #128

Closed
opened 2026-11-12 07:28:19 -05:00 by dohertj2 · 1 comment
Owner

Found while working mxaccessgw#227. RealMxGatewayClient.RunEventLoopAsync stores every event's WorkerSequence as its resume cursor before filtering by family. The gateway's ReplayGap sentinel (family UNSPECIFIED, worker_sequence 0) therefore resets the cursor to 0 on a resume that hits a gap, so the next reconnect gets no replay from the true position. Fix: skip sentinel events (WorkerSequence == 0 / ReplayGap / StreamAttached) before advancing the cursor, with a test. ScadaBridge does not opt into mxgw#227's stream_attached ack, so that message cannot hit it today.

Found while working mxaccessgw#227. RealMxGatewayClient.RunEventLoopAsync stores every event's WorkerSequence as its resume cursor before filtering by family. The gateway's ReplayGap sentinel (family UNSPECIFIED, worker_sequence 0) therefore resets the cursor to 0 on a resume that hits a gap, so the next reconnect gets no replay from the true position. Fix: skip sentinel events (WorkerSequence == 0 / ReplayGap / StreamAttached) before advancing the cursor, with a test. ScadaBridge does not opt into mxgw#227's stream_attached ack, so that message cannot hit it today.
dohertj2 added the type:bugpriority:p3 labels 2026-11-12 07:28:19 -05:00
Author
Owner

Fixed on main 94ae1860. RealMxGatewayClient's resume cursor now only advances (max) and only from real worker events: ReplayGap and any worker_sequence 0 sentinel (incl. a StreamAttached the 0.2.1 contract can't decode) are skipped and never reach the value callback. A ReplayGap anchors the cursor at oldest_available_sequence−1 (the gateway's documented resume point) and logs a Warning naming the lost interval. Tests: 7 new in RealMxGatewayClientResumeCursorTests (4 fail on the old loop); DCL tests 536/0.

Note: not reachable in production today — MxGatewayDataConnection.ConnectAsync builds a new client+session per reconnect, so streams start at cursor 0 and never get a ReplayGap. The IMxGatewayClient doc claiming 'resumes on reconnect' was corrected. If same-session resume is ever wired, add a re-read of subscribed tags on a gap.

Fixed on main 94ae1860. RealMxGatewayClient's resume cursor now only advances (max) and only from real worker events: ReplayGap and any worker_sequence 0 sentinel (incl. a StreamAttached the 0.2.1 contract can't decode) are skipped and never reach the value callback. A ReplayGap anchors the cursor at oldest_available_sequence−1 (the gateway's documented resume point) and logs a Warning naming the lost interval. Tests: 7 new in RealMxGatewayClientResumeCursorTests (4 fail on the old loop); DCL tests 536/0. Note: not reachable in production today — MxGatewayDataConnection.ConnectAsync builds a new client+session per reconnect, so streams start at cursor 0 and never get a ReplayGap. The IMxGatewayClient doc claiming 'resumes on reconnect' was corrected. If same-session resume is ever wired, add a re-read of subscribed tags on a gap.
Sign in to join this conversation.