Skip to content

Commit 46ec8e0

Browse files
authored
Merge pull request #2753 from simonredfern/develop
Improving DB access for broadcastUnreadCounts
2 parents 5d6c3bb + 7d1f256 commit 46ec8e0

File tree

1 file changed

+23
-24
lines changed

1 file changed

+23
-24
lines changed

obp-api/src/main/scala/code/chat/ChatEventPublisher.scala

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package code.chat
33
import code.util.Helper.MdcLoggable
44
import net.liftweb.json
55
import 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

Comments
 (0)