fix(deserializer): heatmap routing drops all actions for unassigned contracts when ds_pool_size = 1#169
Merged
Conversation
In heatmap routing mode, `routeToPool` initialized `selected_q` to 1 and
then applied `selected_q += 1` to convert the 0-indexed heatmap worker id
(dsPoolMap[code][2], built by master with `for (let i = 0; i < pool_size; i++)`)
into a 1-indexed `ds_pool:N` queue name.
When a contract has no heatmap assignment yet (empty dsPoolMap, e.g. fresh or
low-traffic chains, or any contract not seen since the last update_pool_map),
the assignment block is skipped, `selected_q` keeps its init value 1, and the
`+= 1` makes it 2. Traces are then published to `ds_pool:2`. But ds_pool
workers are created with `local_id = i + 1` (i in 0..ds_pool_size-1), consuming
`ds_pool:1..ds_pool_size`. With `scaling.ds_pool_size: 1` only `ds_pool:1`
exists, so everything published to `ds_pool:2` is silently dropped (publishing
to the default exchange with an unrouted queue name is a no-op). Result: blocks
and deltas index fine, but `get_actions` returns 0 and `/v2/health` reports
Elasticsearch Error because the `{chain}-action-*` index is never created.
Public deployments use `ds_pool_size >= 2`, so they never hit this.
Initialize `selected_q` to 0 so an unassigned contract falls back to the first
pool worker (queue `ds_pool:1`), matching the 0-indexed heatmap ids that the
`+= 1` conversion already expects. round_robin and the default case do not rely
on the initial value.
There was a problem hiding this comment.
Code Review
This pull request updates the deserializer worker to initialize selected_q to 0 instead of 1. This ensures that contracts without a heatmap assignment correctly fall back to the first pool worker (queue ds_pool:1) instead of routing to a non-existent ds_pool:2 queue, which previously caused action traces to be silently dropped when ds_pool_size is 1. There are no review comments, so I have no feedback to provide.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
With
scaling.routing_mode: "heatmap"andscaling.ds_pool_size: 1, the indexer ingests blocks and deltas correctly butget_actionsreturns 0 and/v2/healthreports Elasticsearch "Error" because the{chain}-action-*index is never created. All action traces are silently dropped.Root cause
In
MainDSWorker.routeToPool(src/indexer/workers/deserializer.ts), the heatmap path uses 0-indexed worker ids fromdsPoolMap[code][2]and converts them to a 1-indexedds_pool:Nqueue withselected_q += 1.selected_qwas initialized to1. When a contract has no heatmap assignment yet — emptydsPoolMapon a fresh/low-traffic chain, or any contract not seen since the lastupdate_pool_mapIPC update — the assignment block is skipped,selected_qstays1, and+= 1makes it2. Traces are published to{chain}:ds_pool:2.But ds_pool workers are created in
master.tssetupDSPool()withlocal_id = i + 1fori in 0..ds_pool_size-1, consuming queuesds_pool:1..ds_pool_size. Withds_pool_size: 1onlyds_pool:1exists, so a default-exchange publish to the unroutedds_pool:2is a no-op and the traces are lost. Deployments withds_pool_size >= 2happen to have ads_pool:2consumer, so they never observe this.The heatmap worker ids in
dsPoolMap[code][2]are 0-indexed (master builds them withfor (let i = 0; i < pool_size; i++) proposedWorkers.push(i)), andselected_q += 1is exactly the 0→1-index conversion. The init value should therefore represent 0-indexed worker0, i.e. the first pool worker.Fix
Initialize
selected_qto0instead of1, so an unassigned contract falls back to the first pool worker (queueds_pool:1).round_robinreassignsselected_qanddefaultexits, so neither relies on the initial value.Workarounds (for affected users on older builds)
scaling.routing_mode: "round_robin", orscaling.ds_pool_size: 2or higher.Verification
tsccompiles cleanly with no errors. Reproduced and fixed against a local Antelope Spring 1.2.2 node: before the fix, blocks/deltas indexed butget_actions= 0 and ES health = Error; after, a clean re-index produced the chain's full action history (transfer/create/issue/setup/setfeesmap/setcode/newaccount/…) with all four/v2/healthservices OK.Optional follow-up (not in this PR)
A startup warning when
routing_mode === "heatmap" && ds_pool_size < 2would surface the (now-functional but pointless) single-worker-heatmap config explicitly. Happy to add it here or separately if you'd like.