2014-11-21 4 views
0

У меня проблема с сообщениями WebSocket, которые не отправляются с Spring WebSocket версии 4.1.1.RELEASE. Это не происходит с каждым сообщением, только некоторые из них не отправляются по той причине, которую я не понимаю. Содержимое сообщений занимает некоторое время, но я не уверен, что это причина этой проблемы, поскольку иногда она работает, но большую часть времени она не работает.Spring WebSocket - сообщения, потерянные после отправки контроллером

Мое веб-приложение успешно подписывается на канал /user/queue/overview/reqinfo/events, а затем отправляет четыре сообщения для запроса информации. Мой класс контроллера запускает инструкцию COUNT() в базе данных через spring-data-jpa и Hibernate и возвращает результат в виде сообщения пользователю, к которому пришел запрос. Все четыре сообщения обрабатываются одним и тем же способом контроллера, но отправителю отправляется только два ответа. Я извлек соответствующую информацию из журналов Spring и прикрепил их здесь. Как вы можете видеть, последние два сообщения не обрабатываются SimpleBrokerMessageHandler и, таким образом, не отправляются пользователю. Создание содержимого этих сообщений занимает больше минуты.

12:50:54,953 DEBUG clientInboundChannel-12 user.UserDestinationMessageHandler:187 - Translated /user/queue/overview/reqinfo/events -> [/queue/overview/reqinfo/events-user8178efnd] 
12:50:54,953 DEBUG clientInboundChannel-12 broker.SimpleBrokerMessageHandler:175 - Processing SUBSCRIBE /queue/overview/reqinfo/events-user8178efnd id=sub-7 session=8178efnd 
[...] 
12:50:54,957 DEBUG clientInboundChannel-2 support.SimpAnnotationMethodMessageHandler:348 - Searching methods to handle SEND /app/overview/reqinfo/events session=8178efnd 
12:50:54,957 DEBUG clientInboundChannel-1 support.SimpAnnotationMethodMessageHandler:348 - Searching methods to handle SEND /app/overview/reqinfo/events session=8178efnd 
12:50:54,957 DEBUG clientInboundChannel-16 support.SimpAnnotationMethodMessageHandler:348 - Searching methods to handle SEND /app/overview/reqinfo/events session=8178efnd 
12:50:54,959 DEBUG clientInboundChannel-10 support.SimpAnnotationMethodMessageHandler:348 - Searching methods to handle SEND /app/overview/reqinfo/events session=8178efnd 
[...] 
12:50:54,959 DEBUG clientInboundChannel-16 support.SimpAnnotationMethodMessageHandler:446 - Invoking de.d.i.g.websocket.OverviewController#requestOverviewEvents[2 args] 
12:50:54,959 DEBUG clientInboundChannel-10 support.SimpAnnotationMethodMessageHandler:446 - Invoking de.d.i.g.websocket.OverviewController#requestOverviewEvents[2 args] 
12:50:54,959 DEBUG clientInboundChannel-2 support.SimpAnnotationMethodMessageHandler:446 - Invoking de.d.i.g.websocket.OverviewController#requestOverviewEvents[2 args] 
12:50:54,959 DEBUG clientInboundChannel-1 support.SimpAnnotationMethodMessageHandler:446 - Invoking de.d.i.g.websocket.OverviewController#requestOverviewEvents[2 args] 
[...] 
12:50:55,006 DEBUG clientInboundChannel-1 websocket.OverviewController:196 - requestOverviewEvents, incoming message: MsgOverviewEventsRequest(timeframe=THIS_WEEK) 
12:50:55,006 DEBUG clientInboundChannel-10 websocket.OverviewController:196 - requestOverviewEvents, incoming message: MsgOverviewEventsRequest(timeframe=LAST_WEEK) 
12:50:55,006 DEBUG clientInboundChannel-2 websocket.OverviewController:196 - requestOverviewEvents, incoming message: MsgOverviewEventsRequest(timeframe=YESTERDAY) 
12:50:55,006 DEBUG clientInboundChannel-16 websocket.OverviewController:196 - requestOverviewEvents, incoming message: MsgOverviewEventsRequest(timeframe=TODAY) 
[...] 
12:50:55,032 DEBUG clientInboundChannel-16 websocket.OverviewController:225 - requestOverviewEvents, outgoing message: MsgOverviewEvents(timeframe=TODAY, count=31, error=false) 
12:50:55,035 DEBUG clientInboundChannel-16 broker.SimpleBrokerMessageHandler:152 - Processing MESSAGE destination=/queue/overview/reqinfo/events-user8178efnd session=null payload={"timeframe":"TODAY","count":31,"error":false} 
12:50:55,035 DEBUG clientInboundChannel-16 broker.SimpleBrokerMessageHandler:196 - Broadcasting to 1 sessions. 
[...] 
12:51:01,018 DEBUG clientInboundChannel-2 websocket.OverviewController:225 - requestOverviewEvents, outgoing message: MsgOverviewEvents(timeframe=YESTERDAY, count=190292, error=false) 
12:51:01,020 DEBUG clientInboundChannel-2 broker.SimpleBrokerMessageHandler:152 - Processing MESSAGE destination=/queue/overview/reqinfo/events-user8178efnd session=null payload={"timeframe":"YESTERDAY","count":190292,"error":false} 
12:51:01,020 DEBUG clientInboundChannel-2 broker.SimpleBrokerMessageHandler:196 - Broadcasting to 1 sessions. 
[...] 
12:51:19,081 DEBUG clientInboundChannel-1 websocket.OverviewController:225 - requestOverviewEvents, outgoing message: MsgOverviewEvents(timeframe=THIS_WEEK, count=845956, error=false) 
12:51:19,088 DEBUG clientInboundChannel-10 websocket.OverviewController:225 - requestOverviewEvents, outgoing message: MsgOverviewEvents(timeframe=LAST_WEEK, count=1421118, error=false) 

Это пример случая, когда проблема возникает часто. У меня есть другие представления с другими сообщениями и контроллерами, которые страдают от одной и той же проблемы, и их сообщения не занимают минуты, чтобы построить, только несколько секунд или даже меньше. Я использую SimpleMessageBroker с поддержкой SockJS (используя SockJS 0.3.4). При попытке решить эту проблему, я добавил этот компонент в мой класс конфигурации WebSocket вручную установить время ожидания на connecton, но это не решило проблему:

@Bean 
public ServletServerContainerFactoryBean createWebSocketContainer() { 
    long tenMinutesInMillis = 10 * 60 * 1000; 

    ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); 
    container.setAsyncSendTimeout(tenMinutesInMillis); 
    container.setMaxSessionIdleTimeout(tenMinutesInMillis); 

    return container; 
} 

Как это может быть, что некоторые сообщения просто упали, а другие получают правильно отправлен? Если вам нужна дополнительная информация из журналов или исходного кода, спросите пожалуйста.

[UPDATE] Некоторые дополнительные сведения о поведении:

Первое сообщение, которое подсчитывает наименьшее количество элементов всегда возвращается. Второе сообщение возвращает большую часть времени, а последние два не могут быть отправлены примерно в 90% случаев. После того, как они не загрузились, другие представления также не будут загружаться, ответные сообщения просто не отправляются на веб-интерфейс, даже если подписка получена и обработана. После обновления обновления в браузере, чтобы перезагрузить страницу, все работает нормально, пока сообщение не застрянет снова.

Однако система сердцебиения, которая работает в фоновом режиме и использует WebSocket, а также ее сообщения для пользователей, работает все время. Проблема, по-видимому, полностью не затронута этой проблемой.

[UPDATE 2]

Когда проблема возникает, кажется, что sockJsScheduler не обрабатывает все запросы. Сообщение INFO, что WebSocketMessageBrokerStats журналов дают следующий результат:

INFO MessageBrokerSockJS-2 config.WebSocketMessageBrokerStats:113 - WebSocketSession[1 current WS(1)-HttpStream(0)-HttpPoll(0), 1 total, 0 closed abnormally (0 connect failure, 0 send limit, 0 transport error)], stompSubProtocol[processed CONNECT(1)-CONNECTED(1)-DISCONNECT(0)], stompBrokerRelay[null], inboundChannel[pool size = 16, active threads = 0, queued tasks = 0, completed tasks = 120], outboundChannelpool size = 16, active threads = 0, queued tasks = 0, completed tasks = 16], sockJsScheduler[pool size = 8, active threads = 1, queued tasks = 4, completed tasks = 18] 

Он говорит, что есть четыре очередь задачи для sockJsScheduler, которые не обработаны, может быть, эти сообщения, не отправленные правильно? К сожалению, нет никакой дополнительной информации о том, почему они не обрабатываются в журналах.

ответ

2

После интенсивной отладки моего приложения и особенно кода Spring, который обрабатывает, я нашел причину такого поведения.

Проблема не была ни контроллером, ни внутренними процессами Spring, это был класс, который я использую для объектов Principal во время проверки подлинности Spring Security.Он сохраняет последний идентификатор биения, который пользователь ответил успешно, чтобы проверить, жив ли пользователь, который отправляет сообщение в систему, или если сеанс уже считается мертвым. Этот идентификатор был включен в методы equals(), hashCode() и toString() этого объекта.

Весна использует один из этих методов (после некоторого тестирования, я думаю, это toString(), что, по моему мнению, не является хорошим выбором) для перевода маршрутов назначения для @SendToUser операций. Если строка изменяется, что было в случае моего приложения, когда был получен новый идентификатор сердечного ритма, Spring не может перевести путь назначения и не отправит сообщение. Запись в журнале, в которой указано это, скрыта как сообщение уровня TRACE, поэтому я не нашел ее в первую очередь. Сообщение выглядит следующим образом:

14:29:00,260 TRACE clientInboundChannel-16 user.UserDestinationMessageHandler:175 - No user destinations found for /user/RtAuthorizedUser(super=AuthorizedUser(username=SIEM-User 1, authenticated=true, lastAnsweredHeartbeat=9971f9ea-8e64-4c24-823b-f7e6e277c775, alive=true), rtSessionId=RT_SID_iMonitor.443=782acc747aac01b9e0a7ece3ab2d27bd)/queue/overview/reqinfo/events 

Я хотел бы предложить для разработчиков, чтобы сделать это сообщение по крайней мере, уровень DEBUG (или даже WARN или ERROR), так как эта информация трудно обнаружить при поиске проблем в процессе отправки , На самом деле это ошибка.

После удаления идентификатора сердечного ритма из трех указанных методов системы работают хорошо, больше не потерянных сообщений. Так что это была ошибка на моей стороне, но я думаю, что использование toString() здесь не является оптимальным. Теперь Spring может правильно перевести сообщения, создавая эти сообщения (которые являются уровнем DEBUG вместо TRACE, как указано выше):

14:37:35,661 DEBUG clientInboundChannel-3 user.UserDestinationMessageHandler:187 - Translated /user/RtAuthorizedUser(super=AuthorizedUser(username=SIEM-User 1, authenticated=true, alive=true), rtSessionId=RT_SID_iMonitor.443=bf3adbaa858932b64a03724b6137e95d)/queue/overview/reqinfo/events -> [/queue/overview/reqinfo/events-user_qtca5il] 
Смежные вопросы