Skip to content

marketbyorder-bot: track Reset Count per channel - #41

Open
armcconnell wants to merge 2 commits into
mainfrom
feat/mbo-bot-per-channel-reset
Open

marketbyorder-bot: track Reset Count per channel#41
armcconnell wants to merge 2 commits into
mainfrom
feat/mbo-bot-per-channel-reset

Conversation

@armcconnell

Copy link
Copy Markdown
Contributor

Completes the design in #39. Ports the fix merged for the sibling bot in #38.

Problem

A group can carry two redundant publishers interleaved on the same ports, distinguished only by channel_id. Reset Count is per publisher and stays constant while neither is resetting — so two steady-but-different values are the normal state, not a reset.

Coordinator held it as a single uint8, so every alternation between the two publishers tripped the reset barrier and wiped all shard state. On the sibling bot this produced 1.35M spurious barriers, wiping refdata faster than it could be relearned and leaving effectively every book read-out with an empty symbol.

This lane is not currently exposed to it — no market-by-order feed is published today — so this is a latent fix, applied so the bug cannot surface later.

Change

Same shape as #38: key resetCount by channel_id, and scope the wipe to the resetting channel. Shard.reset() becomes resetChannel(ch), deleting only keys whose channel matches.

The one structural difference from the sibling: this shard also owns snapCtx, keyed by snapKey{ch, snap}, and the coordinator owns snapshotRoute on the same key. Both are pruned per channel rather than reassigned wholesale — the sibling has no equivalent maps, so this part has no counterpart in #38.

Every shard is still drained on a barrier: ordering the wipe after all in-flight records is the barrier's job, and any shard may hold records for the resetting channel.

Tests

Two regression tests mirroring #38, both confirmed failing first — and failing for real reasons, not just a build error:

  • interleaved channels with distinct steady Reset Counts run no barrier (against the old code, ~15 of 16 records trip it)
  • a real Reset Count change runs exactly one barrier and spares the other channel's instruments, refdata and snapshot contexts (against the old code the keep assertions fail, because the old reset() reassigned all four maps)

The test harness applies the wipe before acking, so the "did not survive" assertions exercise a real deletion rather than just an ack.

go vet and go test -race are clean, verified independently of the implementing agent.

Notes

  • Coordinator.seqLast is written on every record and never read. Dead bookkeeping, deliberately left alone.
  • metrics.go and shard_test.go are unformatted on main already; left untouched so the diff stays readable rather than burying the change in reformatting.
  • Known limitation, not addressed here: the barrier still calls SnapshotWriter.Reset, whose dirty map is keyed by instrument id with no channel component. So one channel's reset still drops the other channel's pending snapshot work. The effect is a transient skipped snapshot tick that self-heals on the next update for that instrument — not the data-loss class this PR fixes — and it is structurally identical to the merged sibling. Channel-scoping dirty would need its own change.

Port of the market-by-price bot fix. Reset Count is per publisher, and a
group can carry two publishers interleaved on the same ports, so two
steady-but-different values must not be read as a reset.

Key resetCount by channel_id and scope the wipe to the resetting channel.
This shard also owns snapCtx, keyed by (channel, snapshot_id), so
resetChannel clears that too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant