Commit 6d246305 authored by Simon Kirsten's avatar Simon Kirsten
Browse files

Merge branch 'fix-data-race-on-bcast-set' into 'master'

internal/server: fix data race on broadcast set

Closes #1

See merge request stream-server/stream-server!1
parents 2791b3d4 bc0b56c1
Pipeline #26218 passed with stages
in 1 minute and 12 seconds
......@@ -5,6 +5,7 @@ import (
......@@ -32,9 +33,13 @@ var state = displayState{
// clients holds the clients that are connected to the event handler. It is used to broadcast state changes to all SSE (Server-Sent Events) clients.
// Must acquire clientsMu before accessing the map.
// Note: the only reason we use a sse.Client => bool map is that we can call *delete* with the client as key. The actual bool value that is stored holds no significance whatsoever.
// This is basically a *set* in go.
var clients map[*sse.Client]bool = make(map[*sse.Client]bool)
var (
clientsMu sync.Mutex
clients map[*sse.Client]bool = make(map[*sse.Client]bool)
// displayStateHandler updated the state based on the query string.
// For example
......@@ -130,8 +135,21 @@ func displayStateHandler(w http.ResponseWriter, r *http.Request) {
Data: string(body),
// broadcast it to all clients
// We'd like to broadcast the message to all clients, as
// recorded in the clients map. The message send is a
// potentially blocking operation so we don't want to hold the
// lock across send operations. Thus, we first build up a list
// of clients to send to (while holding clientsMu) and start
// sending only after giving up the lock again.
var sendingTo []*sse.Client
for client := range clients {
sendingTo = append(sendingTo, client)
// now broadcast it to all clients
for _, client := range sendingTo {
......@@ -149,11 +167,18 @@ func displayEventsHandler(w http.ResponseWriter, r *http.Request) {
// add client to broadcast set
// Add client to broadcast set. Need to serialize access to clients as
// we're running concurrently with other requests.
clients[client] = true
// remove client from broadcast set on exit
defer delete(clients, client)
defer func() {
delete(clients, client)
body, err := json.Marshal(state)
if err != nil {
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment