@RefreshScope stops @Scheduled task

前端 未结 4 722
心在旅途
心在旅途 2020-12-11 22:48

I have a monitoring app wherein I am running a fixedRate task. This is pulling in a config parameter configured with Consul. I want to pull in updated configuration, so I ad

4条回答
  •  旧时难觅i
    2020-12-11 23:14

    Here's how we've solved this issue.

    /**
     * Listener of Spring's lifecycle to revive Scheduler beans, when spring's
     * scope is refreshed.
     * 

    * Spring is able to restart beans, when we change their properties. Such a * beans marked with RefreshScope annotation. To make it work, spring creates * lazy proxies and push them instead of real object. The issue with * scope refresh is that right after refresh in order for such a lazy proxy * to be actually instantiated again someone has to call for any method of it. *

    * It creates a tricky case with Schedulers, because there is no bean, which * directly call anything on any Scheduler. Scheduler lifecycle is to start * few threads upon instantiation and schedule tasks. No other bean needs * anything from them. *

    * To overcome this, we had to create artificial method on Schedulers and call * them, when there is a scope refresh event. This actually instantiates. */ @RequiredArgsConstructor public class RefreshScopeListener implements ApplicationListener { private final List refreshSchedulers; @Override public void onApplicationEvent(RefreshScopeRefreshedEvent event) { refreshSchedulers.forEach(RefreshScheduler::materializeAfterRefresh); } }

    So, we've defined an interface, which does nothing in particular, but allows us to call for a refreshed job.

    public interface RefreshScheduler {
        /**
         * Used after refresh context for scheduler bean initialization
         */
        default void materializeAfterRefresh() {
        }
    }
    

    And here is actual job, whose parameter from.properties can be refreshed.

    public class AJob implements RefreshScheduler {
        @Scheduled(cron = "${from.properties}")
        public void aTask() {
            // do something useful
        }
    }
    

    UPDATED: Of course AJob bean must be marked with @RefreshScope in @Configuration

    @Configuration
    @EnableScheduling
    public class SchedulingConfiguration {
        @Bean
        @RefreshScope
        public AJob aJob() {
            return new AJob();
        }
    }
    

提交回复
热议问题