Spring MVC WebApp: @schedule: java-sdk-http-connection-reaper: не удалось остановить

У меня есть веб-приложение (с использованием Spring 3.1), которое использует @Scheduled Annotation для периодического выполнения рабочего задания (запланированная задержка). Рабочая задача открывает соединение с AWS DynamoDb и выполняет некоторые чтения/обновления БД. Когда я останавливаю webapp (от менеджера Tomcat), я получаю это сообщение в catalina.out:

"SEVERE: веб-приложение [], похоже, начало поток с именем [java-sdk-http-connection-reaper], но не смог его остановить. Вероятно, это создает утечку памяти."

У меня возникает ощущение, что это связано с тем, что моя запланированная задача все еще работает даже после остановки Tomcat.

@Service
public class TaskScheduler implements ApplicationListener<ContextClosedEvent>{

@Autowired
private WorkerTask workerTask;

AmazonDynamoDBClient myDbConn = null;

   private TaskScheduler() {    
   myDbConn = new AWSConnector("aws.properties").getDynamoConnection();
   }

/*
 * Will be repeatedly called, 10 seconds after the finish of the previous 
 * invocation.
 */
@Scheduled(fixedDelay=100000)
public void process() {
    System.out.println("Scheduling worker task");
            //worker task does some db read/writes
    Future<String> status = workerTask.work(myDbConn);
    if (status.isDone()) {
        System.out.println("Completed Task");
        return;
    }

}

@Override
public void onApplicationEvent(ContextClosedEvent arg0) {
    if(event instanceof ContextClosedEvent) {   
      // TODO Auto-generated method stub
      if(myDbConn != null) {
        this.myDbConn.shutdown();
      }
          }

}

диспетчер-servlet.xml:

<task:annotation-driven scheduler="taskScheduler"/>
<task:scheduler id="taskScheduler" pool-size="2"/>
......
<bean id="TaskScheduler" class="com.sample.TaskScheduler"/>

Я делаю это правильно? a) Я не запускаю TaskScheduler явно. Поэтому я предполагаю, что Spring заботится о запуске этой службы. Вызывается "this.myDbConn.shutdown()". Несмотря на это, я получаю ошибку. Я использую Spring MVC.

Ответ 1

Это, скорее всего, вызвано библиотекой AWS, которая начинает поток в фоновом режиме с именем com.amazonaws.http.IdleConnectionReaper

Вы можете закрыть его, выполнив ServletContextListener, чтобы закрыть его при завершении работы

public class YourListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent contextEvent) {

}

@Override
public void contextDestroyed(ServletContextEvent contextEvent) {

    try {
        com.amazonaws.http.IdleConnectionReaper.shutdown();
    } catch (Throwable t) {
        // log the error
    }
}
}

и добавив это в ваш web.xml

<listener>
    <listener-class>
        your.package.YourListener 
    </listener-class>
</listener>

Ответ 2

У меня была эта проблема, но я решил альтернативное решение для @David_Wartell выше.

Я отследил класс, который создавал оскорбительный объект/объекты из библиотеки Amason aws-java-sdk, которые запускали поток IdleConnectionReaper, но никогда не закрывали (это были com.amazonaws.services.ec2. AmazonEC2Client и com.amazonaws.services.cloudwatch. AmazonCloudWatchClient). Затем я добавил метод destroy() для этого класса, который вызвал статический метод com.amazonaws.http.IdleConnectionReaper.shutdown(). Метод destroy вызывается, когда класс собирает мусор и настраивается с помощью Spring applicationContext.xml. Преимущества этого способа заключаются в том, что он будет работать даже для не-веб-приложений, и он отключит отключение потока из вашего веб-контекста. Правильное решение состоит в том, что классы из библиотеки amazon aws-java-sdk, которые запускают поток IdleConnectionReaper, должны закрыть его, но они этого не делают - отсюда эта ошибка. См. Ссылки и фрагменты кода ниже для моего решения:

applicationContext.xml

<bean id="YourBeanName" class="com.your.package.name.YourBeanName" destroy-method="destroy">
    <!-- other optional configuration goes here -->
</bean>

YourBeanName.java - (класс, создающий оскорбительные объекты амазонки)

    public class YourBeanName {

        // omitted code

        public void destroy() {
            com.amazonaws.http.IdleConnectionReaper.shutdown();
        }

        // omitted code

    }

ссылки:

Форум Amazon - Выключение IdleConnectionReaper
Spring docs - настройка характера bean

Ответ 3

В ответ на ответ Стюарта (и предположим, что вы используете Spring), альтернативу, если вы не используете файлы конфигурации XML:

@Component
public class MyBean {

// ...

    @PreDestroy
    private void cleanUp() {
        try {
            // Shutting down AWS IdleConnectionReaper thread...
            com.amazonaws.http.IdleConnectionReaper.shutdown();
        } catch (Throwable t) {
            // log error
        }
    }

}

Он работал у меня, когда я использовал bean интерфейс com.amazonaws.services.s3.AmazonS3.