Jörn
Jörn

Reputation: 171

How to combine @Scheduled with Profiles

I've got a class that Spring finds via component scan and that has a method annotated with @Scheduled:

@Component
public class Foo {
    ...
    @Scheduled(fixedDelay = 60000)
    public void update() {
        ...

The value 60000 is ok for production, but in my tests I want it to be 1000.
How can I achieve that? E.g., can I combine @Scheduled with profiles somehow?

Upvotes: 3

Views: 2234

Answers (3)

Jörn
Jörn

Reputation: 171

I solved this issue like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans ... xmlns:task="http://www.springframework.org/schema/task"
... xsi:schemaLocation="... http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd ...>

<!-- Everything for "default" profile, including the bean with "@Scheduled(fixedDelay = 60000)" on UpdaterTracker.update() and the "taskScheduler" bean -->
...

<!-- Activate this profile in Arquillian tests -->
<beans profile="arquillian">
    <!-- Update more frequently -->
    <bean id="updaterTracker" class="com.foo.UpdaterTracker"/>
    <task:scheduled-tasks scheduler="taskScheduler">
        <task:scheduled ref="updaterTracker" method="update" fixed-delay="1000"/>
    </task:scheduled-tasks>
</beans>

</beans>

The first part defines the beans as usual, including an instance of the UpdaterTracker-bean that performs update() every 60 seconds. The last part is only activated in case "arquillian" profile is active, defining another instance of the UpdaterTracker-bean and a scheduled task that executes update() every second.

The solution is not perfect, because it produces 2 instances of UpdaterTracker and 3 scheduled tasks. It could be optimized by directly referencing the first UpdaterTracker instance in so that we get 1 instance and 2 scheduled tasks.

However, this works for me and the solution has advantages: It does not require additional beans to be coded and can cope with multiple profiles.

Upvotes: 0

Yevhen Surovskyi
Yevhen Surovskyi

Reputation: 961

Make delay as property:

@Component
    public class Foo {
        ...
        @Scheduled(fixedDelay = ${delay})
        public void update() {

You may keep 2 property files. For example dev.properties and prod.properties Spring will load one of it.

<context:property-placeholder
location="classpath:${spring.profiles.active}.properties" />

Upvotes: 2

george
george

Reputation: 3221

Create two beans, one for production and one for testing and annotate both with @Profile accordingly like below

@Bean
@Scheduled(fixedDelay = 1000)
@Profile("test")
    public void update() {
}

@Bean
@Scheduled(fixedDelay = 60000)
@Profile("dev")
    public void update() {
}

In your unit test class you can switch between them by activating the relevant profile like below

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "classpath:/app-config.xml"
@ContextConfiguration("/app-config.xml")
@ActiveProfiles("dev") //or switch to @ActiveProfiles("test") when testing
public class TransferServiceTest {

    @Autowired
    private TransferService transferService;

    @Test
    public void testTransferService() {
        // test the transferService
    }
}

If @ActiveProfiles("dev") is activated only the dev @scheduled bean will be created otherwise test if the test profile is activated.

Upvotes: 0

Related Questions