miguelgrinberg / flask-sock

Modern WebSocket support for Flask.
MIT License
274 stars 24 forks source link

Flask-Sock and use in GCP AppEngine ? #14

Closed tonyrb closed 2 years ago

tonyrb commented 2 years ago

Hello,

I am trying to run flask-sock over a GCP AppEngine instance. When running the script over it I am having multiple issue:

 Uncaught DOMException: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.
    at HTMLDocument.<anonymous> 

In the HTML header I have: <script>const socket = new WebSocket('wss://' + 'specificdomain.ey.r.appspot.com:8080' + '/customdimfrom0');</script>

I am running the script over a appspot.com subdomain (generated by google) And no error from the console to help find out the current problem.

I am sure it's the way on how the websocket connect to the appengine instance and I am clueless on how to fix this so far. (been trying

Any tips or similar issue when running the library over appengine instance ? Is there additional configuration on the appengine to accept incoming websocket? or maybe need to update the current url to initiate a websocket to the backend.

Thanks !

miguelgrinberg commented 2 years ago

What WSGI server are you using? The only servers that are supported are the ones listed in the documentation. Unfortunately WebSocket is not standardized under WSGI, so each server does it in a different way, you can't assume an unsupported server will just work.

tonyrb commented 2 years ago

Hello Miguel, I am using gunicorn.

Here is the docker file used:

# Use the official lightweight Python image.
# https://hub.docker.com/_/python
FROM python:3.9-slim

# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True

# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./

# Install production dependencies.
RUN pip install --no-cache-dir -r requirements.txt

# Run the web service on container startup. Here we use the gunicorn
# webserver, with one worker process and 8 threads.
# For environments with multiple CPU cores, increase the number of workers
# to be equal to the cores available.
# Timeout is set to 0 to disable the timeouts of the workers to allow Cloud Run to handle instance scaling.
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

Been following this guide from google, and finally trying to run it on Cloud Run instead of Appengine, I have read that AppEngine is not compatible with Websockets (or need to add a flexible instance plus additional modification)

But still having same issue with cloud run and below configuration.

Tony

miguelgrinberg commented 2 years ago

I cannot give you advice on Google Cloud specifically. What I recommend is that you test your Dockerfile locally to make sure that you can connect. If that works, then you have to troubleshoot the connection between Google Cloud and your container. If the local container test does not work, then please include the log output here.

tonyrb commented 2 years ago

Following your advice I manage to make it work on docker locally first with issue then working on how to fix it locally and got the final setup right !!!!

Here is the final setup and it work perfectly on Cloud Run (and probably elsewhere as well).

html:

<script>const socket = new WebSocket('ws://' + 'localhost:8080' + '/customdimfrom0');</script>

end of main.py:

if __name__ == '__main__':
    import os
    app.run(debug=True, threaded=True, host='0.0.0.0',
            port=int(os.environ.get('PORT', 8080)))

dockerfile:

# Use the official lightweight Python image.
# https://hub.docker.com/_/python
FROM python:3.9-slim

# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True

# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./

# Install production dependencies.
RUN pip install --no-cache-dir -r requirements.txt

# Run the web service on container startup. Here we use the gunicorn
# webserver, with one worker process and 8 threads.
# For environments with multiple CPU cores, increase the number of workers
# to be equal to the cores available.
# Timeout is set to 0 to disable the timeouts of the workers to allow Cloud Run to handle instance scaling.
CMD exec gunicorn --bind :8080 --workers 1 --threads 100 --timeout 0 main:app# 

Thanks you Miguel !

miguelgrinberg commented 2 years ago

Glad to hear you figured it out. Thanks for posting the working solution for others to benefit from!

tonyrb commented 2 years ago

Miguel finally I was wrong... When running the docker locally the socket connect to it locally and make it work. But still troublesome when I am online and getting this error now:

WebSocket connection to 'ws://localhost:8080/customdimfrom0' failed:

WebSocket is already in CLOSING or CLOSED state.

So still need to debug it somehow but seems to be linked to GCP cloud run.

tonyrb commented 2 years ago

Quick Update, not an issue with GCP but with my javascript code...

Here is the javascript added:

            socket.onopen = function () {
              socket.send(JSON.stringify(obj))

Issue I was not waiting for the socket to be open resulting to error.

We can close the ticket :)