MM-8710: Web Hub optimizations (#8293)
* webhub optimizations * test fix * minor fix * big perf improvement to ToJson after precomputing * fix hub connection count
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
babd795d79
Коммит
19a5d0047d
@@ -5,6 +5,7 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
@@ -58,11 +59,32 @@ type WebsocketBroadcast struct {
|
||||
TeamId string `json:"team_id"` // broadcast only occurs for users in this team
|
||||
}
|
||||
|
||||
type precomputedWebSocketEventJSON struct {
|
||||
Event json.RawMessage
|
||||
Data json.RawMessage
|
||||
Broadcast json.RawMessage
|
||||
}
|
||||
|
||||
type WebSocketEvent struct {
|
||||
Event string `json:"event"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
Broadcast *WebsocketBroadcast `json:"broadcast"`
|
||||
Sequence int64 `json:"seq"`
|
||||
|
||||
precomputedJSON *precomputedWebSocketEventJSON
|
||||
}
|
||||
|
||||
// PrecomputeJSON precomputes and stores the serialized JSON for all fields other than Sequence.
|
||||
// This makes ToJson much more efficient when sending the same event to multiple connections.
|
||||
func (m *WebSocketEvent) PrecomputeJSON() {
|
||||
event, _ := json.Marshal(m.Event)
|
||||
data, _ := json.Marshal(m.Data)
|
||||
broadcast, _ := json.Marshal(m.Broadcast)
|
||||
m.precomputedJSON = &precomputedWebSocketEventJSON{
|
||||
Event: json.RawMessage(event),
|
||||
Data: json.RawMessage(data),
|
||||
Broadcast: json.RawMessage(broadcast),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *WebSocketEvent) Add(key string, value interface{}) {
|
||||
@@ -83,6 +105,9 @@ func (o *WebSocketEvent) EventType() string {
|
||||
}
|
||||
|
||||
func (o *WebSocketEvent) ToJson() string {
|
||||
if o.precomputedJSON != nil {
|
||||
return fmt.Sprintf(`{"event": %s, "data": %s, "broadcast": %s, "seq": %d}`, o.precomputedJSON.Event, o.precomputedJSON.Data, o.precomputedJSON.Broadcast, o.Sequence)
|
||||
}
|
||||
b, _ := json.Marshal(o)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ package model
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWebSocketEvent(t *testing.T) {
|
||||
@@ -54,3 +56,49 @@ func TestWebSocketResponse(t *testing.T) {
|
||||
t.Fatal("Ids do not match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebSocketEvent_PrecomputeJSON(t *testing.T) {
|
||||
event := NewWebSocketEvent(WEBSOCKET_EVENT_POSTED, "foo", "bar", "baz", nil)
|
||||
event.Sequence = 7
|
||||
|
||||
before := event.ToJson()
|
||||
event.PrecomputeJSON()
|
||||
after := event.ToJson()
|
||||
|
||||
assert.JSONEq(t, before, after)
|
||||
}
|
||||
|
||||
var stringSink string
|
||||
|
||||
func BenchmarkWebSocketEvent_ToJson(b *testing.B) {
|
||||
event := NewWebSocketEvent(WEBSOCKET_EVENT_POSTED, "foo", "bar", "baz", nil)
|
||||
for i := 0; i < 100; i++ {
|
||||
event.Data[NewId()] = NewId()
|
||||
}
|
||||
|
||||
b.Run("SerializedNTimes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
stringSink = event.ToJson()
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("PrecomputedNTimes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
event.PrecomputeJSON()
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("PrecomputedAndSerializedNTimes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
event.PrecomputeJSON()
|
||||
stringSink = event.ToJson()
|
||||
}
|
||||
})
|
||||
|
||||
event.PrecomputeJSON()
|
||||
b.Run("PrecomputedOnceAndSerializedNTimes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
stringSink = event.ToJson()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user