totalcruise
totalcruise

Reputation: 1363

Spring not detecting @Scheduled Methods

I am running Spring 3.2.3.RELEASE and I have several methods within @Service decorated classes that are Scheduled tasks and thus decorated with the @Scheduled annotation.

All the Spring beans are detected and instantiated within the container, however the @Scheduled annotations are never invoked.

I have several application contexts, but the main file is described below as follows:

  <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <import resource="classpath:core-properties.xml" />
    <import resource="classpath:core-datasource.xml" />
    <import resource="classpath:core-task-scheduler.xml" />

    <context:component-scan base-package="com.atlaschase.project.core">
        <context:exclude-filter type="regex"
            expression="com.atlaschase.project.core.services.jms.*" />
        <context:exclude-filter type="regex"
            expression="com.atlaschase.project.core.services.processor.*" />
        <context:exclude-filter type="regex"
            expression="com.atlaschase.project.core.services.remote.*" />
        <context:exclude-filter type="regex"
            expression="com.atlaschase.project.core.bootstrap.populators.*" />
    </context:component-scan>

    <bean id="bufferPopulator" class="com.atlaschase.project.core.services.jms.buffer.BufferPopulator"/>

    <bean id="eventBuffer" class="com.atlaschase.project.core.services.jms.buffer.EventBuffer"/>

    <bean id="processorEventHandler" class="com.atlaschase.project.core.services.jms.buffer.ProcessorEventHandler"/>

The other important file is imported as "core-task-scheduler.xml". This is configured as follows:

    <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>

    <task:executor id="myExecutor" pool-size="1"/>

    <task:scheduler id="myScheduler" pool-size="5"/>

</beans>

Originally, the executor reference (above) was defined in the main application context, but I split this out as an import after reading that other similar problems had been solved in this way. Unfortunately this has not helped. I have also moved the import declarations around, but this seems to have no effect.

Declaring Scheduled methods in the Spring Application Context directly works fine - however I am very keen to use annotations.

Here is the annotated class:

**
 * Service that batches the saving of position updates into a periodically executed
 * process. 
 */
@Service
public class PositionAggregatorService {

    static Logger logger = Logger.getLogger(AircraftPositionAggregatorService.class);

    // The service will not execute within 1 minute of a previous batch attempt.
    // This paramater is updated by a message from another node indicating that
    // they are commencing a batch save of position updates.
    private DateTime blockingTime; 

    private Map<Long, List<Position>> positions;

    @Autowired
    private PositionDao positionDao;

    @Autowired
    private InternalPublisher internalEventPublisher;

    @PostConstruct
    private void initialise(){
        positions = new ConcurrentHashMap<Long, List<Position>>();
    }

    /*
     * Scheduled to execute every 10 minutes as long current time is not
     * before the blocking time threshold.
     * 
     * */
    @Scheduled(fixedRate=6000)
    public void batchSavePositionUpdates(){

        if(blockingTime != null){
            if(DateTime.now(DateTimeZone.UTC).isBefore(blockingTime)){
                return;
            }
        }

        PositionPersistStartedNotification started = new PositionPersistStartedNotification(DateTime.now(DateTimeZone.UTC), DateTime.now(DateTimeZone.UTC).plusMinutes(2));
        internalEventPublisher.publishPositionPersistStartedNotification(started);

        DateTime mostRecentUpdateTime = null;

        List<Position> positionsToSave = new ArrayList<Position>();

        for(Long flightId : positions.keySet()){

            List<Position> positionList = positions.get(flightId);

            for(Position position : positionList){
                if(mostRecentUpdateTime == null){
                    mostRecentUpdateTime = new DateTime(position.getTime());
                }
                else{
                    DateTime positionTime = new DateTime(position.getTime());
                    if(positionTime.isAfter(mostRecentUpdateTime)){
                        mostRecentUpdateTime = positionTime;
                    }
                }
                positionsToSave.add(position);
            }
        }

        Boolean successfulSave = false;

        try{
            positionDao.save(positionsToSave);
            successfulSave = true;
            logger.info(positionsToSave.size() + " Position Updates saved successfully");
        }catch(Exception exception){
            logger.error("Failed to persist latest position updates to database");
            logger.error(exception);
        }


        if(successfulSave){
            removeSavedPositions(mostRecentUpdateTime);
            PositionPersistEndedNotification ended = new PositionPersistEndedNotification(DateTime.now(DateTimeZone.UTC), mostRecentUpdateTime);
            internalEventPublisher.publishPositionPersistEndedNotification(ended);
        }

    }
}

Any help would be appreciated.

Upvotes: 0

Views: 821

Answers (2)

totalcruise
totalcruise

Reputation: 1363

The application was being started by listening for the context to be loaded and then executing a method upon the ContextRefreshedEvent.

When I removed this ApplicationEventListener from the application and simply invoked a public method on the bean to start the service (instead of relying in the ApplicationEventListener) - the application then started normally with all @Scheduled annotations working as expected.

Upvotes: 0

dimitrisli
dimitrisli

Reputation: 21391

Is the Spring context loaded successfully in runtime? I see you have some inconsistencies in namespace definitions where various versions co-exist in the xsd (3.0 and 3.2). Can you try having consistently the same version in these namespaces and try again?

Upvotes: 2

Related Questions