javaspring-bootwebsockethazelcastshedlock

How to fix Websockets and Shedlock compatibility in Spring Boot application


I have a Spring Boot real-time application that uses Websockets with SockJS. Currently I'm scaling my application with LoadBalancer and two instances. Since there are few cron jobs in the app I need to synchronize it between two server for running only one task at a time. For this purpose I used shedlock-spring and shedlock-provider-hazelcast dependencies (I'm also using Hazelcast in the app).

If I add @EnableSchedulerLock(defaultLockAtMostFor = "PT1S") annotation to MainApplication.class application cannot start due to the following error:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stompWebSocketHandlerMapping' defined in class path resource [org/springframework/web/socket/config/annotation/DelegatingWebSocketMessageBrokerConfiguration.class]: 
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: 
Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'stompWebSocketHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: 
@Bean method AbstractMessageBrokerConfiguration.messageBrokerTaskScheduler called as a bean reference for type [org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler] but overridden by non-compatible bean instance of type [com.sun.proxy.$Proxy136]. 
Overriding bean of same name declared in: class path resource [org/springframework/web/socket/config/annotation/DelegatingWebSocketMessageBrokerConfiguration.class]

@SchedulerLock annotation works fine, because I tested it in the separate app, but it seems that it conflicts with Websockets and overrides some beans. I'm new to Websockets configuration, so please help if someone knows the reason of this error and how to fix it.

Here is my Websocket configuration that works perfectly:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/socket")
                .setAllowedOrigins("*")
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app")
                .enableSimpleBroker("/notification");
    }
}

Solution

  • ShedLock by default creates a proxy around ThreadPoolTaskScheduler and it seems that Spring Websockets require ThreadPoolTaskScheduler instance.

    You can switch ShedLock to AOP proxy mode like this @EnableSchedulerLock(mode = PROXY_METHOD, defaultLockAtMostFor = "PT1S") See more information in the documentation. (As a side note, 1 second lockAtMostFor time is quite short, if you do not specify otherwise, all locks will be released after 1s)