meshery / meshery/meshkit

broadcaster.broadcast() blocking send lets one stalled subscriber freeze Register/Unregister for everyone

Open
#1,092 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
223
Forks
225
Avg merge
7d 1h
Merged PRs (30d)
1

Description

In `utils/broadcast/broadcaster.go`, `broadcast()` sends to each registered channel with a plain blocking `ch <- m`:

```go
func (b *broadcaster) broadcast(m BroadcastMessage) {
for ch := range b.outputs {
ch <- m
}
}
```

`Register`, `Unregister` and `Submit` all funnel through the same single `run()` goroutine (the `select` in `run`). If any one registered subscriber stops draining its channel, `broadcast()` blocks forever on that send, which wedges `run()`, which means every other subscriber stops receiving messages and every subsequent `Register`/`Unregister` call blocks indefinitely too - not just for the stalled subscriber, for the whole broadcaster.

This pattern is inherited from the reference implementation this file's header cites (`github.com/dustin/go-broadcast`) - upstream's `broadcast()` has the identical unprotected send, so it isn't a meshkit-introduced regression, but it's a real gap in an exported, shared-library type that any consumer of `Broadcaster` can hit.

Note on current reach: I checked `meshery/meshery`'s server and its GraphQL subscriptions currently use their own separate channels, not `Broadcaster.Register`, so this isn't actively triggered in that codepath today - but the exported type ships the bug for any current or future caller (adapters, other services) that does call `Register`.

Reproduced on `origin/master` (cf39c57): a test registering a slow (never-drained) and a fast subscriber, submitting one message, and asserting the fast subscriber still gets it and a follow-up Register/Unregister each return within 2s. Fails on current master (fast subscriber times out); passes with a `select`+`default` fix in `broadcast()`.

Will open a PR shortly with the fix + regression test.

Contributor guide

Open the contributing guide

Research direction

Start in utils/broadcast/broadcaster.go, focusing on broadcast() and the run() goroutine that handles Register, Unregister, and Submit. Reproduce the stalled and fast subscriber scenario described in the issue, then add a regression test showing that the fast subscriber and follow-up registration operations still complete; run the Go tests to verify the behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
75/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.