Skip to content

Commit

Permalink
send fewer crowd websocket events in very large rooms
Browse files Browse the repository at this point in the history
we have broadcasts with 10k+ members.
the most frequent message sent to all members is `crowd`, once per
second.
if the room contains more than 100 members,
we only send `crowd` 10% of the time.
if the room has 1000 members, we send 1% of the time.

importantly, if the named users of the crowd change, then we always
send the message. That's necessary to know which contributors and
streamers are present.
  • Loading branch information
ornicar committed Sep 20, 2024
1 parent a480cf8 commit 23c306a
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 10 deletions.
16 changes: 10 additions & 6 deletions src/main/scala/actor/RoomActor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,16 @@ object RoomActor:
None -> None

case crowd: ClientIn.Crowd =>
if crowd == state.lastCrowd then None -> None
else
Some {
deps.clientIn(crowd)
state.copy(lastCrowd = crowd)
} -> None
val shouldSend =
if crowd == state.lastCrowd then false
else if crowd.users != state.lastCrowd.users then true
else if crowd.members > 1000 && crowd.members % 100 != 0 then false
else if crowd.members > 100 && crowd.members % 10 != 0 then false
else true
if shouldSend then
deps.clientIn(crowd)
Some(state.copy(lastCrowd = crowd)) -> None
else None -> None

case SetTroll(v) =>
Some(state.copy(isTroll = v)) -> None
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/ipc/ClientIn.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ object ClientIn:
def payload(js: JsValue) = Payload(JsonString(Json.stringify(js)))
def payload(tpe: String, js: JsonString) = Payload(JsonString(cliMsg(tpe, js)))

case class Crowd(doc: JsObject) extends ClientIn:
case class Crowd(doc: JsObject, members: Int, users: Set[User.Id]) extends ClientIn:
lazy val write = cliMsg("crowd", doc)
val emptyCrowd = Crowd(Json.obj())
val emptyCrowd = Crowd(Json.obj(), 0, Set.empty)

case class LobbyPairing(fullId: Game.FullId) extends ClientIn:
def write =
Expand Down
6 changes: 4 additions & 2 deletions src/main/scala/ipc/CrowdJson.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ final class CrowdJson(inquirers: Inquirers, mongo: Mongo, lightUserApi: LightUse
keepOnlyStudyMembers(crowd).map: users =>
crowd.copy(users = users, anons = 0)
else Future.successful(crowd)
}.flatMap(spectatorsOf(_, crowd.users)).map(ClientIn.Crowd.apply)
}.flatMap(spectatorsOf(_, crowd.users)).map(ClientIn.Crowd(_, crowd.members, crowd.users.toSet))

def round(crowd: RoundCrowd.Output): Future[ClientIn.Crowd] =
spectatorsOf(
Expand All @@ -26,7 +26,9 @@ final class CrowdJson(inquirers: Inquirers, mongo: Mongo, lightUserApi: LightUse
"white" -> (crowd.players.white > 0),
"black" -> (crowd.players.black > 0),
"watchers" -> spectators
)
),
crowd.room.members,
Set.empty
)
}

Expand Down

0 comments on commit 23c306a

Please sign in to comment.