8

I have an application that uses websockets (STOMP over SockJs), with Spring at the backend. Application works fine (websockets) on localhost on Tomcat but when I deploy to Heroku or AWS Web Sockets stop working. My websocket configuration in Angular2

        let sockjs = new SockJS('/rest/add?jwt=' + this.authService.getToken(), {"devel":true,"debug":true}, {"transports":["websocket"]});

I also tried with

{"disabled_transports":["websocket"]}

but both are failing. web.xml

 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1">

<context-param>
    <param-name>spring.profiles.default</param-name>
    <param-value>default</param-value>
</context-param>

<servlet>
    <servlet-name>ws</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/spring/ws-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>ws</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/rest/*</url-pattern>

</filter-mapping>
</web-app>

websocket in spring

    <websocket:message-broker
    application-destination-prefix="/app">
    <websocket:stomp-endpoint path="/add">
        <websocket:sockjs/>
    </websocket:stomp-endpoint>
    <websocket:simple-broker prefix="/topic, /queue" />
</websocket:message-broker>

URL to my application on Heroku so you can check by yourself in console of your web browser. Link Please see updated logs, this piece makes me worried No TransportHandler

CJyb2xlcyI6IkNVU1RPTUVSIn0.wFqNOduN-lD1-9GIRnG1X1aLJZTxtz9c6vmO7jmPPiE2017-04-06T16:23:32.439917+00:00 app[web.1]: 2017-04-06 16:2332 WARN  DefaultSockJsService:239 - No TransportHandler for http://myapp-ws.herokuapp.com/rest/add/097/eyocvxic/websocket?jwt=eyJhbGciOiJI
Cœur
  • 37,241
  • 25
  • 195
  • 267
Lukasz
  • 691
  • 1
  • 12
  • 30
  • 1
    Your logs irrelevenant, check vegur logs - mayge vegur configured incorrectly and drops websocket connections. And don't disable websocket, you need websocket enabled. – user1516873 Apr 03 '17 at 07:47
  • I can see in the logs H27 error https://devcenter.heroku.com/changelog-items/662 but nothing about what has to be changed on Heroku (the cause might be that I have a free account instead of a paid one). I also created a ticket with Heroku support team to have a look at this. – Lukasz Apr 03 '17 at 09:35
  • I upgraded account to paid and it still doesn't work – Lukasz Apr 03 '17 at 17:27
  • 1
    I am not expert on heroku. I suppose your connection is broken by proxy/load balancer, but i can't help you with this, sorry. – user1516873 Apr 04 '17 at 07:01
  • I will add bounty to this ticket as soon as it's eligible (in 7 hours). – Lukasz Apr 04 '17 at 08:57
  • Two things that I have found, one is paramter that needs to be enabled for socket.io is _heroku features:enable http-session-affinity_ (not sure if it is relevant for sockjs (STOMP)), I've already enabled it and it didn't help. And the second on Heroku website examples, if you look into source code of those (http://sockjs.herokuapp.com/example-cursors.html) examples you will find _client_opts = {"url":"//sockjs.herokuapp.com","disabled_transports":["websocket"],"sockjs_opts":{"devel":true,"debug":true}};_ – Lukasz Apr 04 '17 at 09:19
  • 1
    This examples doesn't work for me - websocket connection drops immediately with 404 http status. Maybe it is Heroku issue. As alternative can try OpenShift - it declares websockets support and has free plans – user1516873 Apr 04 '17 at 10:05
  • 1
    http-session-affinity - parameter for sticky session, used in load balancing. Useful if you have cluster with at least 2 instances without sharing sessions between it. For example - here is configuration for apache, which is working as proxy and load balancer for 2 tomcat instances, just to illustrate complexity http://stackoverflow.com/a/42578769/1516873 Heroku uses Verur as proxy and it should have similar settings. – user1516873 Apr 04 '17 at 10:18
  • @user1516873 - do you possibly recognize WARN in the updated log line? – Lukasz Apr 06 '17 at 16:33

1 Answers1

11

ok, so finally I made it working. Turned out that Tomcat on heroku does not have the standard set of libraries. First I deployed locally on webapp-runner https://devcenter.heroku.com/articles/java-webapp-runner after which I I saw a strange error. I tested with a few libraries and finally after after adding

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-websocket</artifactId>
    <version>8.5.11</version>
</dependency>

and

<build>
...
<plugins>
    ...
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.3</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals><goal>copy</goal></goals>
                <configuration>
                    <artifactItems>
                        <artifactItem>
                            <groupId>com.github.jsimone</groupId>
                            <artifactId>webapp-runner</artifactId>
                            <version>8.5.11.3</version>
                            <destFileName>webapp-runner.jar</destFileName>
                        </artifactItem>
                    </artifactItems>
                </configuration>
            </execution>
        </executions>
    </plugin>
</plugins>

I got it working locally. Then I added PROCFILE with following content

web:    java $JAVA_OPTS -jar myapp-ws/target/dependency/webapp-runner.jar --port $PORT myapp-ws/target/*.war

and committed to GITHUB (I have git integrated with Heroku), triggered build from within Heroku and it works.

Lukasz
  • 691
  • 1
  • 12
  • 30
  • Bump 1 because you not only solved your problem, but you left the answer here for the next coder. – Richard_G Apr 08 '17 at 19:36
  • Thanks Lukasz. Now do we still need "webapp-runner" and "tomcat-embed-websocket" to utilize Websockets on Heroku ?. I am upgrading webapp-runner to 8.5.27.0. However I think it is better if we can run App directly on Tomcat deployed by Heroku. – Thang Le Feb 03 '18 at 05:18
  • Both webapp-runner & tomcat-embed-websocket are redundant when you move your app to Spring Boot and run it as a jar – Lukasz Feb 08 '18 at 19:38
  • Yes, i still working with Spring classic. But i think tomcat 8.5.30 already integrated tomcat-websocket.jar so now it does not request to have: tomcat-embed-websocket but of course still need webapp-runner 8.5.30. Anyway, thanks – Thang Le Apr 19 '18 at 12:05