У меня есть прослушиватель кролика amqp в Springboot, он зависает, не закрывая приложение

В моем фактическом коде есть следующий фрагмент кода. У меня есть несколько потребителей, слушающих очередь.

 @RabbitListener
 private void abc(ETLConfigDTO config){
  try{
   log.info("load started");
   loadService.loadData(config);
  }
  catch(Exception e){
   log.error("Load failed"):
  }
  finally{
   log.info("finished processing"):
  }
 }

loadData () занимает от нескольких минут до нескольких часов обработки. Это своего рода обработка etl. Внутри этого метода есть интенсивное ведение журнала, поэтому я знаю, в каком состоянии находится процесс. Проблема в том, что процесс застрял внутри метода loadPlans (). Сообщение в очереди находится в неподтвержденном состоянии, поскольку оно все еще обрабатывается, что мне нужно таким образом. Нет никаких исключений, так как catch ничего не печатает или даже блок finally. У меня также есть весенний cron (интервал 5 минут) в том же классе, который также работает нормально и выполняет свои задачи.

Следует отметить, что это работает нормально, если я не использую rabbit amqp.

Есть ли пропадание соединения / сети? Или какой-то таймаут? Или основной поток завис / мертв? Я действительно не понимаю, что здесь происходит.

Заранее спасибо.

ОБНОВИТЬ: Спасибо Гэри, Я вижу это в jstack 19:

"SimpleAsyncTaskExecutor-1" #25 prio=5 os_prio=0 tid=0x00007f5615b3d800 nid=0x2f runnable [0x00007f56703cd000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:171)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
        at sun.security.ssl.InputRecord.read(InputRecord.java:503)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:983)
        - locked <0x000000067a6bada8> (a java.lang.Object)
        at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:940)
        at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
        - locked <0x000000067a6baea0> (a sun.security.ssl.AppInputStream)
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
        - locked <0x000000067a717cb8> (a java.io.BufferedInputStream)
        at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:735)
        at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1569)
        - locked <0x000000067a6b4b60> (a sun.net.www.protocol.https.DelegateHttpsURLConnection)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
        - locked <0x000000067a6b4b60> (a sun.net.www.protocol.https.DelegateHttpsURLConnection)
        at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)
        at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:48)
        at org.springframework.http.client.AbstractClientHttpResponse.getStatusCode(AbstractClientHttpResponse.java:33)
        at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:56)
        at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50)
        at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:602)
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:570)
        at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:530)
        at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:448)
..
...
...
...


Please advise.

НОВОЕ ОБНОВЛЕНИЕ: У меня увеличена память -XX: MaxMetaspaceSize = 1024M -Xms4096M -Xmx4096M

Поток сейчас застревает на соединении оракула.

"SimpleAsyncTaskExecutor-1" #25 prio=5 os_prio=0 tid=0x00007ff6102c8800 nid=0x33 runnable [0x00007ff619ad9000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:171)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at oracle.net.ns.Packet.receive(Packet.java:300)
        at oracle.net.ns.DataPacket.receive(DataPacket.java:106)
        at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:315)
        at oracle.net.ns.NetInputStream.read(NetInputStream.java:260)
        at oracle.net.ns.NetInputStream.read(NetInputStream.java:185)
        at oracle.net.ns.NetInputStream.read(NetInputStream.java:102)
        at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:124)
        at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:80)
        at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1137)
        at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:290)
        at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
        at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
        at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:193)
        at oracle.jdbc.driver.T4CStatement.executeForRows(T4CStatement.java:1033)
        at oracle.jdbc.driver.OracleStatement.executeBatch(OracleStatement.java:4536)
        - locked <0x00000007b01c6b20> (a oracle.jdbc.driver.T4CConnection)
        at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:230)
        at org.springframework.jdbc.core.JdbcTemplate$1BatchUpdateStatementCallback.doInStatement(JdbcTemplate.java:572)
        at org.springframework.jdbc.core.JdbcTemplate$1BatchUpdateStatementCallback.doInStatement(JdbcTemplate.java:559)
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:405)
        at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:611)
...
...

Вы можете разместить файл свойств?

Jonathan JOhx 05.01.2019 05:23

Я настроил кролика через beans

Anirudh Negi 05.01.2019 06:14
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
2
815
1

Ответы 1

Ваш слушатель довольно необычный; в большинстве случаев это будет void listen(SomeObject), где слушатель обрабатывает объект и завершает работу, а сообщение подтверждается.

Похоже, вы игнорируете содержимое сообщения и просто используете его присутствие для запуска loadData().

Тем не менее, по умолчанию сообщение не будет подтверждено, пока метод не завершится; поток контейнера останется в методе слушателя, пока он не завершится.

По умолчанию для контейнера установлен режим подтверждения AUTO, что означает, что контейнер автоматически подтвердит (или отклонит) сообщение при выходе из метода.

Вы можете изменить режим подтверждения на NONE, что означает, что RabbitMQ вообще не требует подтверждения и немедленно удалит сообщение.

Однако поток контейнера по-прежнему будет выполняться в методе до выхода из метода.

Сообщение будет потеряно, если приложение выйдет из строя.

Извините, что обновил слушателя, он читает сообщение и обрабатывает его в loadData ()

Anirudh Negi 06.01.2019 16:12

Так в чем же вопрос? Как я уже сказал, нормально оставлять сообщение неподтвержденным до завершения загрузки и выхода слушателя, если только вы не измените режим подтверждения на NONE.

Gary Russell 06.01.2019 16:39

Вопрос в том, что основной поток застревает в loadData (), чего не должен ... Он остается там навсегда ..

Anirudh Negi 07.01.2019 07:25

Но это ваш код и не имеет ничего общего с фреймворком, поэтому мы ничего не можем с этим поделать - сделайте дамп потока, чтобы увидеть, что он делает.

Gary Russell 07.01.2019 15:11

Как я могу это сделать? Есть ли способ зарегистрировать активность потока?

Anirudh Negi 07.01.2019 15:23

Есть несколько способов. например JDK поставляется с инструментом jstack, просто найдите pid jvm (например, с jps).

Gary Russell 07.01.2019 15:27

Спасибо, Гэри, выше я обновил трассировку стека с помощью команды jstack. Вроде есть блокировка. Посоветуйте, пожалуйста, что нужно сделать, чтобы этого избежать?

Anirudh Negi 07.01.2019 16:40
at java.net.SocketInputStream.socketRead0(Native Method) - похоже, вы заблокированы в ожидании каких-то данных от HTTP-сервера; это совершенно не связано с spring-amqp; Я предлагаю вам отладить это самостоятельно.
Gary Russell 07.01.2019 16:45

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

Anirudh Negi 07.01.2019 16:54

Привет, Гэри! Обновите новую трассировку стека. это связано с блокировками БД?

Anirudh Negi 08.01.2019 09:13

Я здесь, чтобы поддержать фреймворки, над которыми работаю; У меня нет времени помогать вам отлаживать код вашего приложения. at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(Oracl‌​eStatementWrapper.ja‌​va:230) - на этот раз он ожидает результата от базы данных - возможно, вы можете добавить в свое приложение ведение журнала отладки, чтобы показать прогресс (чтение с FTP, запись в базу данных и т. д.).

Gary Russell 08.01.2019 14:44

Другие вопросы по теме