@@ -3,7 +3,7 @@ package code.chat
33import code .util .Helper .MdcLoggable
44import net .liftweb .json
55import net .liftweb .json .Serialization .write
6- import scala . concurrent .{ Future , ExecutionContext }
6+ // No async imports needed — broadcastUnreadCounts runs synchronously (1-2 fast queries)
77
88/**
99 * Publishes chat events to ChatEventBus after REST operations.
@@ -49,6 +49,9 @@ object ChatEventPublisher extends MdcLoggable {
4949 is_online : Boolean
5050 )
5151
52+ /** Unread count event. The unread_count field is an increment (e.g. 1 for a new message),
53+ * not an absolute count. Clients should add this to their local total.
54+ * Exact counts are reconciled via the GET /users/current/chat-rooms/unread REST endpoint. */
5255 case class UnreadEvent (
5356 chat_room_id : String ,
5457 unread_count : Long
@@ -60,7 +63,7 @@ object ChatEventPublisher extends MdcLoggable {
6063 publishMessageEvent(" new" , msg, senderUsername, senderProvider, senderConsumerName)
6164 // Sending a message means the sender has "read" the room up to this point
6265 ParticipantTrait .participantProvider.vend.updateLastReadAt(msg.chatRoomId, msg.senderUserId)
63- Future { broadcastUnreadCounts(msg) }( ExecutionContext .global )
66+ broadcastUnreadCounts(msg)
6467 }
6568
6669 def afterUpdate (msg : ChatMessageTrait , senderUsername : String , senderProvider : String , senderConsumerName : String ): Unit = {
@@ -97,37 +100,33 @@ object ChatEventPublisher extends MdcLoggable {
97100 }
98101
99102 /**
100- * Broadcast unread counts to affected participants after a new message.
103+ * Broadcast unread count increments to affected participants after a new message.
101104 *
102- * "Open rooms" (isOpenRoom=true)
103- * only notify users who are explicitly @mentioned, to avoid generating
104- * hundreds of thousands of publish events for large rooms .
105+ * Instead of computing exact counts (which requires a DB query per participant),
106+ * we send an increment of 1. Clients can add this to their local count.
107+ * Exact counts are reconciled on page load via the REST endpoint .
105108 *
106- * Private rooms notify all participants except the sender.
109+ * "Open rooms" (isOpenRoom=true) only notify explicitly @mentioned users.
110+ * Private rooms notify all explicit participants except the sender.
107111 *
108- * Unread counts respect a 60-day cutoff — older messages are ignored .
112+ * Uses only 2 DB queries total (room + participants), not N+2 .
109113 */
110114 private def broadcastUnreadCounts (msg : ChatMessageTrait ): Unit = {
111115 try {
112116 val room = ChatRoomTrait .chatRoomProvider.vend.getChatRoom(msg.chatRoomId)
113117 val isOpenRoom = room.map(_.isOpenRoom).openOr(false )
114118
115- val participants = ParticipantTrait .participantProvider.vend
116- .getParticipants(msg.chatRoomId).openOr(List .empty)
117-
118- for (p <- participants if p.userId != msg.senderUserId) {
119- if (isOpenRoom) {
120- // Open rooms: only notify explicitly mentioned users
121- if (msg.mentionedUserIds.contains(p.userId)) {
122- val count = ChatMessageTrait .chatMessageProvider.vend
123- .getUnreadMentionCount(msg.chatRoomId, p.userId, p.lastReadAt).openOr(0L )
124- afterUnreadCountChange(p.userId, msg.chatRoomId, count)
125- }
126- } else {
127- // Private rooms: notify all participants
128- val count = ChatMessageTrait .chatMessageProvider.vend
129- .getUnreadCount(msg.chatRoomId, p.userId, p.lastReadAt).openOr(0L )
130- afterUnreadCountChange(p.userId, msg.chatRoomId, count)
119+ if (isOpenRoom) {
120+ // Open rooms: only notify explicitly mentioned users — no DB query needed
121+ for (userId <- msg.mentionedUserIds if userId != msg.senderUserId) {
122+ afterUnreadCountChange(userId, msg.chatRoomId, 1L )
123+ }
124+ } else {
125+ // Private rooms: notify all participants except the sender
126+ val participants = ParticipantTrait .participantProvider.vend
127+ .getParticipants(msg.chatRoomId).openOr(List .empty)
128+ for (p <- participants if p.userId != msg.senderUserId) {
129+ afterUnreadCountChange(p.userId, msg.chatRoomId, 1L )
131130 }
132131 }
133132 } catch {
0 commit comments