diff --git a/CTFd/__init__.py b/CTFd/__init__.py index c2212dec..2c74a776 100644 --- a/CTFd/__init__.py +++ b/CTFd/__init__.py @@ -134,6 +134,7 @@ def create_app(config='CTFd.config.Config'): # If you have multiple workers you must have a shared cache socketio.init_app( app, + async_mode=app.config.get('SOCKETIO_ASYNC_MODE'), message_queue=app.config.get('CACHE_REDIS_URL') ) diff --git a/CTFd/config.py b/CTFd/config.py index 930e4d57..153b119e 100644 --- a/CTFd/config.py +++ b/CTFd/config.py @@ -184,12 +184,19 @@ class Config(object): APPLICATION_ROOT: Specifies what path CTFd is mounted under. It can be used to run CTFd in a subdirectory. Example: /ctfd + + SOCKETIO_ASYNC_MODE: + Specifies what async mode SocketIO should use. The simplest but least performant option is 'threading'. + Switching to a different async mode is not recommended without the appropriate load balancing mechanisms + in place and proper understanding of how websockets are supported by Flask. + https://flask-socketio.readthedocs.io/en/latest/#deployment ''' REVERSE_PROXY = os.getenv("REVERSE_PROXY") or False TEMPLATES_AUTO_RELOAD = (not os.getenv("TEMPLATES_AUTO_RELOAD")) # Defaults True SQLALCHEMY_TRACK_MODIFICATIONS = (not os.getenv("SQLALCHEMY_TRACK_MODIFICATIONS")) # Defaults True UPDATE_CHECK = (not os.getenv("UPDATE_CHECK")) # Defaults True APPLICATION_ROOT = os.getenv('APPLICATION_ROOT') or '/' + SOCKETIO_ASYNC_MODE = os.getenv('SOCKETIO_ASYNC_MODE') or 'threading' ''' === OAUTH === diff --git a/CTFd/utils/events/__init__.py b/CTFd/utils/events/__init__.py index 2b60bcc3..9ca8c160 100644 --- a/CTFd/utils/events/__init__.py +++ b/CTFd/utils/events/__init__.py @@ -2,4 +2,4 @@ from flask_socketio import SocketIO # The choice to use threading is intentional to simplify deployment. # At the moment it is not recommended to build full-duplex systems inside CTFd. -socketio = SocketIO(async_mode='threading') +socketio = SocketIO()