New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Redis / Eventlet / Flask-SocketIO #618
Comments
I figured out what's causing the issue, the |
There is another problem in your code. When you initialize a Since in this case we are using a delayed initialization due to the use of the app factory function, the socketio = SocketIO(async_mode='eventlet')
def create_app(debug=False):
# ...
socketio.init_app(app, message_queue='redis://')
return app |
Thanks. Will the following also work (everything in init_app) ?
so that I can follow my existing implementation for registering extensions ? |
Yes, that is actually better when you are using the delayed initialization style. |
Thanks, got it to work on my MacOSX with On Windows (Cygwin), no luck. It works fine without the As soon as I add
If you're interested, here is the project. |
Can you debug it a bit to see if the problem is in writing to redis or reading from it? |
I just gave up on making it work on Windows and switched to an Ubuntu box. It works fine there as well... I'm pretty busy at the moment but you can always clone the fork I linked to reproduce on Windows. |
@miguelgrinberg sorry to resuscitate something so old, but not putting the initialization arguments into the call to |
@viggyfresh the way to use |
Sounds good, no problem |
I just spent hours debugging this until I stumbled upon this thread. I must say this is very confusing and needs to be documented. Application factory pattern is merely a way to plug the app into an instantiated extension at a later time. There is nothing at all that would hint a user that a certain argument can only be provided during |
This is incorrect. The SocketIO extension works in the same way as most other extensions. You can initialize it in a single step: socketio = SocketIO(app) or in two steps: socketio = SocketIO()
def create_app():
app = Flask(__name__)
socketio.init_app(app)
return app Both work, so I still don't see what was the source of confusion. The only unusual thing about the SocketIO extension is that it has this "passive" mode, where it is initialized without a Flask app. But the same rules apply. You can initialize a passive SocketIO object in one or two steps. |
Sure, that's all clear. Confusion comes from the fact that one could think that the following is a valid approach: socketio = SocketIO(message_queue='amqp://')
def create_app():
app = Flask(__name__)
socketio.init_app(app)
return app There's nothing in any of the official docs anywhere that suggests that any extra arguments ( Passing arguments to extensions is not too common (as they're usually configured through Flask config variables) - but when the arguments are provided directly, in every extension I've come across it doesn't matter if the arguments are provided when instantiating the extension, or later when binding to the app. That's because they just merge both sets of arguments, and then initialize the extension. |
Yes, this is because the extension works as all other extensions, you can provide args in either place. You must have had a very specific issue that you are not describing. The code example that you shared where
Correct. The goal is that this extension works in the same way. If you have a specific case in which it doesn't, I can fix it.
You need to show me an actual example in which this is broken, because a simple test based on your example worked fine for me. I would not recommend people to split the args in two places though, and that is why I commented against it in this issue. |
Hi Miguel, I write in other place a question but I think is more relevent here. |
Eventlet is unlikely to work well with pyaudio, which is a C package. Not much we can do about it, greenlets are kinda picky, they work well with Python code but not so much with native code. |
hi @miguelgrinberg - this hit us a really long time back, so I cannot remember the exact specifics, but I believe a situation where the arguments don't work uniformly in both spots is the following:
In this case, IIRC, what would happen is we'd hit the Flask route, but nothing would ever get sent through the message queue (and thus no emit). Simply moving the Not sure if this is helpful! |
Hi Miguel, thanks for your answer, so maybe I need some advice here, can do this:do a portaudio server in C, connect to socket with flask python code with asyncio, send and receiv with flask-socketio & eventlet.Do you think that will be more performant than flask-socketio without eventlet?The thing is I dont want to loose the easy of use of flask and go to everything in C.What do you think? Regards
Mariano E. Deleu marianodeleu@yahoo.com.ar
El sábado, 11 de julio de 2020 16:55:20 ART, Miguel Grinberg <notifications@github.com> escribió:
Eventlet is unlikely to work well with pyaudio, which is a C package. Not much we can do about it, greenlets are kinda picky, they work well with Python code but not so much with native code.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
Communication via socket should work fine, and would allow you to use websocket on the server, so yes, that is a good option. |
@miguelgrinberg I can confirm that this does not work; you must put |
@mgd722 That's okay, it was not a usage that I intended to support anyway. What I'm going to do when I get a moment is make sure an error is displayed if the extension is used in that way. |
That makes sense. Most of my confusion came from your previous comment "...the extension works as all other extensions, you can provide args in either place." An error to tell users when it's configured incorrectly sounds like a perfectly appropriate solution. For simplicity for myself and other future Googlers, this is the working configuration: from flask import Flask
from flask_socketio import SocketIO
# does not work
# socketio = SocketIO(message_queue='redis://')
# does work
socketio = SocketIO()
def create_app(debug=False):
"""Create an application."""
# ...your create app stuff goes here
# does not work
# socketio.init_app(app)
# does work
socketio.init_app(app, message_queue='redis://')
return app |
This hit me as well. I was debugging this for a few days and it took me a while to nail down that it was related to the fact that I was using pubsub (in all of my efforts to reproduce the issue I naively left out the The reason I put the
And I figured the same The solution is to create to separate instances, one for "emitting only" (which I just create adhoc and let the garbage collector remove later) and one for the actual application server (which lives in memory for as long the application is alive). I understand that maybe the letter of the law may say this does not need to be documented, but I think many users of this library would benefit from a brief mention of this "two instance" strategy and in actuality it may end up saving many hours of debugging. |
@skamensky What you are doing is not a good idea. The "active" Socket.IO instance is a superset of the "passive" one, so there is no need to create a second instance if you want to emit. Just use the first one. All you need to do is to put the arguments to your active Socket.IO instance in one place. Either in the |
@miguelgrinberg , the issue is that the Other non-web processes and threads are also able to communicate to the clients and create a new Thank you very much for all of your help! |
@skamensky sorry, but no, this does not make sense to me. To be able to emit, you need the "active" Socket.IO instance created and running. If this instance isn't running, then there is no way for clients to connect, or for any threads to emit.
For non-web processes I agree 100%. This is the intended use of the "passive" Socket.IO instance. Non-web threads living in the same process as the active instance do not need a passive instance. Just import the active instance and use it to emit to clients directly. |
I think we're on the same page and there's some sort of semantic misunderstanding. I will therefore take this quote as a blessing 😊
And revisit this one as penance for my sin of disobedience if I ever happen in to unexplained silent failures 🙃.
Again, cheers for all the help! You are a true champ. |
I wish I had come across this hours ago! A callout in the docs about this would be immensely helpful for relative newbies like myself attempting to implement Flask-SocketIO using the app factory pattern. Glad this solved it though 🍻 |
This is a duplicate of #1130 which is now fixed. |
I am unable to make the combination (Redis / Eventlet / SocketIO) work.
I have forked your Flask-SocketIO-Chat to demonstrate this bug here (branch:
eventlet-redis-bug
) .Adding
message_queue='redis://'
toSocketIO
init, the chat is not working properly anymore (it seems messages are not flowing through the websocket). Redis is running properly on localhost:6379.Here is the sample init code:
app/__init__.py
chat.py
Steps to reproduce:
The text was updated successfully, but these errors were encountered: