Skip to content

add total stream/consumer counts to meta snapshot stats#7980

Draft
alexbozhenko wants to merge 1 commit intomainfrom
track_total_stream_and_consume_counts
Draft

add total stream/consumer counts to meta snapshot stats#7980
alexbozhenko wants to merge 1 commit intomainfrom
track_total_stream_and_consume_counts

Conversation

@alexbozhenko
Copy link
Copy Markdown
Member

Signed-off-by: Your Name your.email@example.com

@synadia-claude-reviewer
Copy link
Copy Markdown

synadia-claude-reviewer bot commented Mar 23, 2026

Claude finished @alexbozhenko's task in 1m 42s —— View job


PR Review

  • Gather context
  • Analyze changed files
  • Post review

Two issues found:

1. Data race (critical) — server/monitor.go:3040-3041

totalStreamCount and totalConsumerCount are written with atomic.StoreInt64 in encodeMetaSnapshot, but read without atomic loads in metaClusterSnapshotStats. The race detector will flag this. The fix is to use atomic.LoadInt64(...) matching the existing pattern for lastMetaSnapTime/lastMetaSnapDuration just above.

2. Stale counts when all streams are deleted — server/jetstream_cluster.go:2147-2151

The if len(out) == 0 early return (before the atomic-store block) is taken when there are no streams, so totalStreamCount and totalConsumerCount are never updated to 0. A cluster that had N streams and then had all of them deleted would continue to show the old counts until the next non-empty snapshot. The fix is to move the count stores before (or duplicate them in) the early-return branch.

snap.LastDuration = time.Duration(durationNanos)

}
snap.TotalStreamCount = uint64(cluster.totalStreamCount)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Data race: totalStreamCount and totalConsumerCount are written with atomic.StoreInt64 in encodeMetaSnapshot, but read here without atomic loads. The race detector will flag this.

Suggested change
snap.TotalStreamCount = uint64(cluster.totalStreamCount)
snap.TotalStreamCount = uint64(atomic.LoadInt64(&cluster.totalStreamCount))
snap.TotalConsumerCount = uint64(atomic.LoadInt64(&cluster.totalConsumerCount))

This matches the existing pattern used for lastMetaSnapTime and lastMetaSnapDuration just above.

Comment on lines 2147 to +2150
if cc := js.cluster; cc != nil {
atomic.StoreInt64(&cc.lastMetaSnapTime, start.UnixNano())
atomic.StoreInt64(&cc.lastMetaSnapDuration, int64(took))
atomic.StoreInt64(&cc.totalStreamCount, int64(nsa))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if len(out) == 0 early return on the non-diff path (before this block) skips these stores. So if all streams are deleted, totalStreamCount and totalConsumerCount remain at their previous non-zero values rather than being updated to 0.

Consider moving the entire atomic-store block (or at least the count stores) to before the len(out) == 0 check, since nsa and nca are fully computed by that point.

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