В моем приложении есть список publisherPostListenerList
, который получает сообщения пользователя реального времени из очереди RabbitMQ, которые будут отправлены подписчикам/потребителям. Список является свойством класса ApplicationListener
, который прослушивает события очереди pubsub. Следующий метод контроллера извлекает элементы списка с помощью метода getter & на основе логики, толкает сообщения к подписчикам.Создание списка для кластерной среды
поток выглядит следующим образом
Пользователь пишет пост -> сообщение попадет в БД + Очередь -> Сообщения от очереди добавляются в списке, который publisherPostListenerList
для толкания абонентов пользователя.
Как мы видим, publisherPostListenerList
является общим списком для n одновременных запросов из-за того, что ApplicationListener
является синглом. Для одного экземпляра настройка работает нормально, но не будет работать в кластерной среде, так как каждый узел будет иметь свой собственный список publisherPostListenerList
.
Как я могу справиться с этой ситуацией? Я не могу сделать ApplicationListener
class stateless Мне нужен список для хранения элементов сообщения, полученных из очереди. Я помещаю список в распределенный в кеш памяти? Или есть какой-то другой обычный способ?
ApplicationListener.java
@Component
public class ApplicationEventListener {
private List<Post> publisherPostListenerList = new CopyOnWriteArrayList<Post>();
private static final Logger logger = Logger.getLogger(ApplicationEventListener.class);
@EventListener
public void postSubmissionEventHandler(PostSubmissionEvent event) throws IOException {
Post post = event.getPost();
logger.debug("application published user post received " + post);
publisherPostListenerList.add(post);
}
public List<Post> getPublisherPostListenerList() {
return publisherPostListenerList;
}
public void setPublisherPostListenerList(List<Post> publisherPostListenerList) {
this.publisherPostListenerList = publisherPostListenerList;
}
}
метод контроллера для толкания сообщения абоненту
@RequestMapping(value="/getRealTimeServerPushUserPosts")
public SseEmitter getRealTimeServerPushUserPosts(@RequestParam("userId") int userId){
SseEmitter sseEmitter = new SseEmitter();
CustomUserDetail myUserDetails = currentUserAccessor.getCurrentLoggedInUser();
User loggedInUser=myUserDetails.getUser();
List<Integer> userPublisherIDList = this.userService.loadUserPublisherIdListWhichLoggedInUserFollows(loggedInUser);
List<Post> postList =eventListener.getPublisherPostListenerList();
for(Integer userPublisherId : userPublisherIDList){
for(Post post:postList){
if((userPublisherId.intValue()) == (post.getUser().getUserId().intValue())){
try {
sseEmitter.send(post);
postList.remove(post); //removes the post for all the subscribers as the list acts as a global list.
} catch (IOException e) {
logger.error(e);
}
}
}
}
return sseEmitter;
}
кто будет вызывать метод контроллера? – developer
Я использую события, отправленные сервером, чтобы отправить сообщение клиенту/loggedInUser – underdog
, почему вы не можете использовать базу данных вместо этого? – developer