2013-08-05 7 views
10

Ho un'applicazione Web (utilizzando Spring 3.1) che utilizza l'annotazione @Scheduled per eseguire periodicamente un'attività di lavoro (ritardo pianificato). L'attività di lavoro apre una connessione a AWS DynamoDb e esegue alcuni read/updates del DB. Quando interrompo la webapp (da Tomcat manager) ottengo questo messaggio in catalina.out:Spring MVC WebApp: @schedule: java-sdk-http-connection-reaper: impossibile arrestare

"SEVERE: l'applicazione Web [] sembra aver avviato un thread denominato [java-sdk-http-connection-reaper] ma non è riuscito a fermarlo, è molto probabile che crei una perdita di memoria. "

Ho la sensazione che questo abbia qualcosa a che fare con il mio task programmato ancora in esecuzione anche dopo l'arresto di 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(); 
     } 
      } 

} 

dispatcher-servlet.xml:

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

me lo fa fare correttamente? a) Non avvio esplicitamente TaskScheduler. Quindi presumo che la primavera si occupi di avviare questo servizio. Viene chiamato 'this.myDbConn.shutdown()'. Nonostante questo, ottengo l'errore. Sto usando Spring MVC.

risposta

12

Questo è probabilmente causato dalla biblioteca AWS, che avvia un thread in background denominata com.amazonaws.http.IdleConnectionReaper

È possibile spegnerlo mediante l'attuazione di un ServletContextListener per chiuderla alla chiusura

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 
    } 
} 
} 

e l'aggiunta di questo al vostro web.xml

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

Mi piace questa risposta anche se sotto potrebbe funzionare. Dal momento che sto consumando SDK AWS da un altro contenitore di cui non sono a conoscenza internals. –

7

ho avuto questo problema come bene, ma ho deciso per una soluzione alternativa a @ David_Wartell di sopra.

ho rintracciato la classe che stava creando un oggetto incriminato/oggetti dalla libreria di AWS-java-sdk di Amazon che stavano cominciando il filo IdleConnectionReaper ma mai lo spegnimento (questi erano com.amazonaws.services.ec2. AmazonEC2Client e com.amazonaws.services.cloudwatch. AmazonCloudWatchClient). Quindi ho aggiunto un metodo destroy() a questa classe che ha chiamato il metodo statico com.amazonaws.http.IdleConnectionReaper.shutdown(). Il metodo destroy viene chiamato quando la classe è garbage collection e viene configurata utilizzando Spring applicationContext.xml. I vantaggi di farlo in questo modo sono che funzionerà anche per applicazioni non web e disaccoppierà l'arresto del thread dal tuo contesto web. La soluzione corretta è che le classi della libreria amazon aws-java-sdk che avviano il thread IdleConnectionReaper dovrebbero spegnerlo ma non lo fanno, quindi questo bug. Vedere riferimenti e frammenti di codice di seguito per la mia soluzione:

applicationContext.xml

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

YourBeanName.java - (classe che crea gli oggetti offendere amazon)

public class YourBeanName { 

     // omitted code 

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

     // omitted code 

    } 

riferimenti:

Amazon forum - Shutting down IdleConnectionReaper
Spring docs - Customizing the nature of a bean

+0

Bello, buona risposta. – bobmarksie

+0

Utilizzo di Tomcat + Spring. Esattamente la soluzione che stavo cercando per risolvere la causa di questo messaggio di errore. – Joseph

2

In cima a risposta di Stuart (e supponendo che si sta utilizzando primavera), un alternativa se non si utilizzano file di configurazione 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 
     } 
    } 

} 

Ha funzionato per me, quando ho utilizzato un bean che implementava l'interfaccia com.amazonaws.services.s3.AmazonS3.