Коммит 214f21c1 создал по автору Radch-enko's avatar Radch-enko
Просмотр файлов

- Enhance push notification handling with deduplication logic and header-based processing.

- Simplify successful update mapping in `RoomRepositoryImpl`.
- Add debounce to `ResourceDisposerUseCase` for efficient data refresh.
- Update `.gitignore` to exclude deployment scripts and directories.
владелец 3e138bae
......@@ -82,3 +82,5 @@ coverage/
/oldProject/
/clients/tablet/composeApp/google-services.json
/local.properties
/deploy-backend.sh
/deploy/
......@@ -9,6 +9,7 @@ import band.effective.office.backend.feature.notifications.service.INotification
import org.slf4j.LoggerFactory
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.servlet.http.HttpServletRequest
/**
* Controller for Google calendar push notifications
......@@ -21,6 +22,9 @@ class CalendarNotificationsController(
) {
private val logger = LoggerFactory.getLogger(CalendarNotificationsController::class.java)
// Set to store previously seen message numbers for deduplication
private val processedMessageNumbers = mutableSetOf<String>()
/**
* Endpoint for receiving Google calendar push notifications
*/
......@@ -29,9 +33,50 @@ class CalendarNotificationsController(
summary = "Receive Google calendar push notification",
description = "Endpoint for receiving push notifications from Google Calendar"
)
fun receiveNotification(@RequestBody(required = false) payload: String?): ResponseEntity<Void> {
logger.info("Received push notification: \n{}", payload)
notificationSender.sendEmptyMessage("booking")
fun receiveNotification(
@RequestBody(required = false) payload: String?,
request: HttpServletRequest
): ResponseEntity<Void> {
// Extract headers for deduplication
val messageNumber = request.getHeader("X-Goog-Message-Number")
val resourceState = request.getHeader("X-Goog-Resource-State")
logger.info("Received push notification: messageNumber={}, resourceState={}, payload=\n{}",
messageNumber, resourceState, payload)
// Check if this is a duplicate notification
if (messageNumber != null) {
if (processedMessageNumbers.contains(messageNumber)) {
logger.info("Skipping duplicate notification with message number: {}", messageNumber)
return ResponseEntity.ok().build()
}
// Add to processed set for future deduplication
processedMessageNumbers.add(messageNumber)
// Limit the size of the set to prevent memory leaks
if (processedMessageNumbers.size > 1000) {
// Remove the oldest entries (assuming they're added in order)
val toRemove = processedMessageNumbers.size - 1000
processedMessageNumbers.toList().take(toRemove).forEach {
processedMessageNumbers.remove(it)
}
}
} else {
logger.warn("Received notification without X-Goog-Message-Number header")
}
// Process the notification
// Note: For duplicate notifications, we've already returned at line 51,
// so this code is only executed for non-duplicate notifications
// Only send message if resourceState is "exists"
if (resourceState == "exists") {
notificationSender.sendEmptyMessage("booking")
} else {
logger.info("Skipping notification with resourceState: {}", resourceState)
}
return ResponseEntity.ok().build()
}
}
\ Нет новой строки в конце файла
}
......@@ -36,12 +36,7 @@ class RoomRepositoryImpl(
.map { response ->
when (response) {
is Either.Error -> Either.Error(ErrorWithData(response.error, null))
is Either.Success -> {
// When we receive booking updates, fetch the latest room information
// This is a workaround since we can't directly convert BookingResponseDTO to RoomInfo
val roomsInfo = runCatching { getRoomsInfo() }.getOrNull()
roomsInfo ?: Either.Success(emptyList())
}
is Either.Success -> Either.Success(emptyList())
}
}
}
......
......@@ -7,6 +7,8 @@ import kotlinx.coroutines.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
/**
......@@ -25,7 +27,7 @@ class ResourceDisposerUseCase(
operator fun invoke() {
updateJob = scope.launch {
networkRoomRepository.subscribeOnUpdates().collect {
networkRoomRepository.subscribeOnUpdates().debounce(2000).collectLatest {
refreshDataUseCase()
}
}
......
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать