Search code examples
pythonmysqlmonkeypatchinggevent-socketiogreenlets

max_user_connections after gevent.monkey.patch_all()


I am using gevent-socketio v0.13.8 for a chat application on a django based web app. My database is MySql and have a max_user_connection = 1500 value. My socket server is daemonized with python daemon. I was using the socket server without monkey patching and it was running good, except when there was an error on a greenlet, all system fails with SystemExit and no connection could be established anymore. The solution was to restart all server.

However I don't want to restart the server everytime. And finally I came up with the idea monkey patching. I don't know if it is relevant to my problem but I want my socket server to run even if an unhandled exception causes a SystemExit on a greenlet.

Then I used gevent.monkey.patch_all() in my server start function. And here is my main problem right now: After 3-4 connections, MySql causes the following error:

User xxx already has more than 'max_user_connections' active connections

max_user_connection variable is set to 1500 in mysql server. I think something creates new connection to database in greenlets.

By the way max_user_connection error does not appear when I use:

monkey.patch_all(socket=True, dns=True, time=True, select=True, thread=True, os=True, ssl=True, httplib=True, aggressive=True)

instead of:

monkey.patch_all()

Is there a way to use monkey patching without getting this error? If I forgot to give any information on the problem definition please let me know and I will update it immediately

And here is my daemonized server code:

class App():

    def __init__(self):
        self.stdin_path = 'xxx.txt'
        self.stdout_path = 'xxx.txt'
        self.stderr_path = 'xxx.txt'
        self.pidfile_path =  'xxx.pid'
        self.pidfile_timeout = 5

    def run(self):
        from socketio.server import SocketIOServer
        from gevent import monkey
        monkey.patch_all()
        while True:
            try:
                bind = ("xx.xx.xx.xx", xxxx)
                handler = get_handler()
                server = SocketIOServer(bind, handler, resource="socket.io",policy_server=False)
                server.serve_forever()
            except:
                server.kill()
app = App()
logger = logging.getLogger("DaemonLog")
logger.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler = logging.FileHandler("xxx.log")
handler.setFormatter(formatter)
logger.addHandler(handler)

daemon_runner = runner.DaemonRunner(app)
daemon_runner.daemon_context.files_preserve=[handler.stream]
daemon_runner.do_action()

Solution

  • I have found a solution for my problem at: https://github.com/abourget/gevent-socketio/issues/174

    it is actually related with non closed database connections of greenlets. After adding a similar exception_handler_decorator in my namespace class I have not see the max_user_connection errors

    from django.db import close_old_connections  # Django 1.6
    class MyNamespace(BaseNamespace):
        ...
        def exception_handler_decorator(self, fun):
            def wrap(*args, **kwargs):
                try:
                    return fun(*args, **kwargs)
                finally:
                    close_old_connections()
            return wrap
        ...