Websocket (ws4py in Python 3.5) not working in Docker container

1.2k Views Asked by At

I have a simple web application that uses CherryPy for a RESTful backend and ws4py for websockets.

1) Javascript client sends a POST to Python backend
2) Python replies with a unique id
3) Javascript connects to the websocket and sends the unique id
4) Python associates the websocket client connection to the unique id

Python websocket code:

class WebSocketHandler(WebSocket):
def __init__(self, *args, **kw):
    WebSocket.__init__(self, *args, **kw)
    print('Connected to websocket server!')
    SUBSCRIBERS.add(self)

def received_message(self, message):
    print('Websocket identified itself?')
    SUBSCRIBERS_WITH_ID[message.data] = self

Python CherryPy code:

cherrypy.config.update({'server.socket_host': 0.0.0.0,
                        'server.socket_port': 8080})

cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)

WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tools.websocket = WebSocketTool()

cherrypy.tree.mount(
    DummyAPI(), '/api/dummy', config={
        '/': {
            'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
            'tools.CORS.on': True
        }
    }
)

cherrypy.tree.mount(
    WebSocketAPI(), '/ws', config={
        '/': {
            'tools.websocket.on': True,
            'tools.websocket.handler_cls': WebSocketHandler
        }
    }
)

cherrypy.engine.start()
cherrypy.engine.block()

Javascript code:

POST to API:

var req = new XMLHttpRequest();
req.onload = function (e) {
    console.log('Response code: ' + req.responseText);
    result_id = req.responseText;
    websocketConnect();
};
req.open('POST', api_url);
req.send();

Websocket section:

function websocketConnect() {
websocket = new WebSocket(websocket_url);
websocket.onopen = function (evt) { 
      console.log("Connected to WebSocket server.");
      websocket.send(result_id)};

This works fine on my machine and deployed on Amazon EC2. However, when I try to deploy it in a Docker container, the websockets don't work.

Here is my Dockerfile:

FROM python
MAINTAINER xxx

RUN pip3.5 install cherrypy ws4py
RUN mkdir /var/www

COPY python /var/www/python

EXPOSE 8080

CMD ["/usr/local/bin/python3.5", "/var/www/python/simplews.py"]

Output when I run from Docker:

sudo docker run  -v /tmp/dockertmp/:/tmp/ -p 8080:8080 -i 563a51d13f59
[23/Oct/2015:10:09:00] ENGINE Bus STARTING
[23/Oct/2015:10:09:00] ENGINE Starting WebSocket processing
[23/Oct/2015:10:09:00] ENGINE Started monitor thread '_TimeoutMonitor'.
[23/Oct/2015:10:09:00] ENGINE Started monitor thread 'Autoreloader'.
[23/Oct/2015:10:09:01] ENGINE Serving on http://0.0.0.0:8080
[23/Oct/2015:10:09:01] ENGINE Bus STARTED
172.17.42.1 - - [23/Oct/2015:10:09:08] "POST ..."
Connected to websocket server!

It never reaches the stage where the Javascript file is able to send data through the websocket. Chrome debug shows the WS state as "Pending".

However, when I exit the CherryPy application in Docker, the websocket message comes through:

enter code here
sudo docker run  -v /tmp/dockertmp/:/tmp/ -p 8080:8080 -i 563a51d13f59
[23/Oct/2015:10:15:30] ENGINE Bus STARTING
[23/Oct/2015:10:15:30] ENGINE Starting WebSocket processing
[23/Oct/2015:10:15:30] ENGINE Started monitor thread '_TimeoutMonitor'.
[23/Oct/2015:10:15:30] ENGINE Started monitor thread 'Autoreloader'.
[23/Oct/2015:10:15:30] ENGINE Serving on http://0.0.0.0:8080
[23/Oct/2015:10:15:30] ENGINE Bus STARTED
172.17.42.1 - - [23/Oct/2015:10:15:33] "POST ..."
Connected to websocket server!
^C[23/Oct/2015:10:15:35] ENGINE Keyboard Interrupt: shutting down bus
[23/Oct/2015:10:15:35] ENGINE Bus STOPPING
[23/Oct/2015:10:15:40] ENGINE HTTP Server     cherrypy._cpwsgi_server.CPWSGIServer(('0.0.0.0', 8080)) shut down
[23/Oct/2015:10:15:40] ENGINE Stopped thread '_TimeoutMonitor'.
[23/Oct/2015:10:15:40] ENGINE Terminating WebSocket processing
[23/Oct/2015:10:15:40] ENGINE Stopped thread 'Autoreloader'.
[23/Oct/2015:10:15:40] ENGINE Bus STOPPED
[23/Oct/2015:10:15:40] ENGINE Bus EXITING
[23/Oct/2015:10:15:40] ENGINE Bus EXITED
[23/Oct/2015:10:15:40] ENGINE Waiting for child threads to terminate...
Websocket identified itself?

Output when I run it without Docker:

python3.5 python/simplews.py 
[23/Oct/2015:06:09:45] ENGINE Bus STARTING
[23/Oct/2015:06:09:45] ENGINE Starting WebSocket processing
[23/Oct/2015:06:09:45] ENGINE Started monitor thread '_TimeoutMonitor'.
[23/Oct/2015:06:09:45] ENGINE Started monitor thread 'Autoreloader'.
[23/Oct/2015:06:09:45] ENGINE Serving on http://0.0.0.0:8080
[23/Oct/2015:06:09:45] ENGINE Bus STARTED
127.0.0.1 - - [23/Oct/2015:06:09:48] "POST ..."
Connected to websocket server!
Websocket identified itself?

In the non-Docker case the websocket identifies itself immediately. I can't figure this out. Is the websocket receiver thread stuck somehow in Docker?

The suspicious part from the Docker logs is when the application exits, the websocket received message finally arrives:

[23/Oct/2015:10:15:40] ENGINE Waiting for child threads to terminate...
Websocket identified itself?
1

There are 1 best solutions below

0
On BEST ANSWER

Replacing the Python multiprocessing module with threading.Thread fixed the problem. I was using multiprocessing in the POST method handler.

Here's the commit with the fix on the actual project:

https://github.com/sevagh/youtube-audio-dl/commit/9e23ae174f8791206b934608a1d4d702b411d18e