2015-05-13 18 views
11

Sto provando a convertire la configurazione XML per l'utilizzo del framework delle attività di Spring in configurazione puramente di codice. Sono in grado di riprodurre la funzionalità ma ogni volta che spengo la guerra sul server Tomcat su cui vive l'utilità di pianificazione, si blocca (non si blocca con la configurazione XML). Ho eseguito il debug per ispezionare le istanze di scheduler ed executor, ma non vedo una differenza, quindi non sono sicuro di cosa potrebbe causarne il blocco.Conversione della configurazione XML del task Spring per la configurazione del codice

Ecco la configurazione XML che funziona:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd"> 

    <task:executor id="com.work.gwx.pix.executor" 
     pool-size="${pix.job.executor.pool.size:1-40}" 
     queue-capacity="${pix.job.executor.queue.capacity:0}" 
     rejection-policy="CALLER_RUNS"/> 

    <task:scheduler id="com.work.gwx.pix.scheduler" pool-size="${pix.job.scheduler.pool.size:4}" /> 

    <task:annotation-driven executor="com.work.gwx.pix.executor" scheduler="com.work.gwx.pix.scheduler" /> 

    <bean id='queueProcessor' class="com.work.gwx.queueing.QueueProcessor" /> 

</beans> 

Ecco il codice di configurazione:

@EnableAsync 
@EnableScheduling 
@Configuration 
public class TaskConfiguration implements AsyncConfigurer, SchedulingConfigurer { 

    @Value("${pix.job.executor.max.pool.size:1}") 
    private int executorMaxPoolSize; 

    @Value("${pix.job.executor.queue.capacity:0}") 
    private int executorQueueCapacity; 

    @Value("${pix.job.scheduler.pool.size:4}") 
    private int schedulerPoolSize; 

    @Bean(destroyMethod = "shutdown") 
    public Executor pixTaskScheduler() { 
     final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, new ThreadPoolTaskExecutor()); 
     // ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); 
     return ex; 
    } 

    @Bean 
    public Executor pixExecutor() { 
     final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
     executor.setCorePoolSize(executorMaxPoolSize); 
     executor.setQueueCapacity(executorQueueCapacity); 
     executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 
     executor.setThreadFactory(new ThreadPoolTaskExecutor()); 
     executor.initialize(); 
     return executor; 
    } 

    @Override 
    public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) { 
     taskRegistrar.setScheduler(pixTaskScheduler()); 

    } 

    @Override 
    public Executor getAsyncExecutor() { 
     return pixExecutor(); 
    } 

    @Override 
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { 
     return new SimpleAsyncUncaughtExceptionHandler(); 
    } 
} 

Quando uso setExecuteExistingDelayedTasksAfterShutdownPolicy(false) nel codice di configurazione che fa arrestare, ma io sono preoccupato che la forza avere effetti negativi poiché è impostato su true quando viene eseguito tramite la configurazione XML. Inoltre, dovrei notare, la classe QueueProcessor sta facendo il lavoro che voglio e non mi dispiace se le esecuzioni in ritardo vengono cancellate - Non voglio che i thread in esecuzione attualmente vengano cancellati bruscamente.

Questo è il messaggio che ottengo quando si blocca:

GRAVI: L'applicazione web [/ pix-queue-processor] sembra avere ha iniziato una discussione chiamato [ThreadPoolTaskExecutor-1], ma non è riuscita a fermalo. È molto probabile che questo crei una perdita di memoria.

Qualche idea su cosa potrebbe causare l'impiccagione? Oppure, utilizzerei quel metodo commentato permettimi di fare ciò che voglio (non ucciderò un'attività in esecuzione ma annullerò i compiti in ritardo)?

+0

Uno dei problemi che vedo è che stai impostando un nuovo 'ThreadPoolTaskExecutor' come' ThreadFactory'? Perché? Ora hai fondamentalmente 2 esecutori di compiti in cui uno è controllato e l'altro in realtà no. –

+0

Un'altra cosa è perché non stai collegando il tuo 'TaskExecutor' al tuo 'TaskScheduler'? Che sta usando, ancora un altro' TaskExecutor non gestito'. –

risposta

4

La tua configurazione basata su Java non è realmente una rappresentazione della configurazione XML. Ci sono almeno 2 cose che sono diverse.

  1. tuo TaskExecutor ha un'altra TaskExecutor cablata come ThreadFactory questo non è il caso in XML e anche inizia un'altra TaskExecutor.
  2. Il TaskScheduler utilizza un nuovo TaskExecutor mentre la configurazione xml utilizza quella configurata.

L'hanno finito il vostro compito in arresto è possibile impostare la proprietà waitForTasksToCompleteOnShutdown sul TaskExecutor per true allora ogni attività in sospeso saranno completate e non saranno accettate nuove attività.

Anche la chiamata a initialize non dovrebbe essere necessaria in quanto il metodo afterPropertiesSet verrà chiamato da Spring, che a sua volta chiama initialize.

I 2 definizioni seguenti fagioli sono più in linea con la configurazione XML (e ora avete un singolo TaskExecutor invece di 3 e sarà prima finire i compiti prima dello spegnimento.

@Bean(destroyMethod = "shutdown") 
public Executor pixTaskScheduler() { 
    final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, pixExecutor()); 
    // ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); 
    return ex; 
} 

@Bean 
public Executor pixExecutor() { 
    final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
    executor.setCorePoolSize(executorMaxPoolSize); 
    executor.setQueueCapacity(executorQueueCapacity); 
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 
    executor.setWaitForTasksToCompleteOnShutdown(true); 
    return executor; 
} 
+0

Mi spiace di non aver ancora risposto a questo dato che ero fuori città. Sembra promettente e dovrebbe essere in grado di testarlo presto. Ha senso quello che stai dicendo. – AHungerArtist

+0

Sembra funzionare, ma una domanda in più: nell'XML, sono in grado di fornire un nome/id sia all'esecutore che allo schedulatore. Come potrei farlo tramite codice? Il ThreadPoolTaskExecutor sembra avere un metodo ma non quello programmato. Ciò aiuterebbe davvero a identificare quali thread provengono da questo durante il debug. – AHungerArtist

+0

No perché non esiste un solo pool di thread. Per 'ThreadPoolTaskExecutor' puoi usare' threadNamePrefix' per aggiungere un prefisso. Ma lo schedulatore è solo uno schedulatore che usa il singolo 'ThreadPoolTaskExecutor' per avviare le attività. Se non vuoi che sia necessario aggiungere un altro task executor, ma questo non è ciò che hai (o hai) nella tua configurazione xml. –

Problemi correlati