Search code examples
pythonsql-serverdjangogunicorngevent

Django and SQL Server, gevent compliant


I would like to use a SQL Server database in a Django app that I can scale in the future.

The app would be I/O bound, so I thought the best way to make it scalable is to use Gunicorn with the gevent worker class.

The problem is that for using Gunicorn with --worker-class gevent the Django app should be gevent compliant and usually happens that some database clients aren't compatible (eg: mysqlclient lib).

I found this SQL Server backend for Django: https://pypi.org/project/django-mssql-backend/ but I'm not able to understand if it is gevent compliant (aka "green").

I know that it would be so if it only uses standard socket/networking python libs that can be easily monkey-patched but I can't understand if this is the case. Is pyodbc SQL Server backend gevent compliant?

On the official manual and on Google I can't find further information.


Solution

  • If you are willing to switch to Postgresql, I have a module already setup to do everything you need:

    Python Postgres psycopg2 ThreadedConnectionPool exhausted

    This includes a connection pool to handle thousands of simultaneous connections.

    ** Update **

    I have a solution using Pymssql:

    import gevent.socket
    import pymssql
    import traceback
    import sys
    
    def wait_callback(read_fileno):
        gevent.socket.wait_read(read_fileno)
    
    pymssql.set_wait_callback(wait_callback)
    
    def conn():
        return pymssql.connect(server=server, user=user, password=password, autocommit=True)
    
    def fetchone(SQL, *args):
        with conn() as c:
            with c.cursor() as cursor:
                try:
                    cursor.execute(SQL, args)
                except TypeError:
                    cursor.execute(SQL, args[0])
                except Exception as exc:
                    print(sys._getframe().f_back.f_code)
                    print(sys._getframe().f_back.f_code.co_name)
                    traceback.print_exc()
                    return ()
                return cursor.fetchone()
    
    def fetchall(SQL, *args):
        with conn() as c:
            with c.cursor() as cursor:
                try:
                    cursor.execute(SQL, args)
                except TypeError:
                    cursor.execute(SQL, args[0])
                except Exception as exc:
                    print(sys._getframe().f_back.f_code)
                    print(sys._getframe().f_back.f_code.co_name)
                    traceback.print_exc()
                    return ()
                return cursor.fetchall()
    
    def execute(PSQL, *args):
        with conn() as c:
            with c.cursor() as cursor:
                try:
                    cursor.execute(PSQL, args)
                except TypeError:
                    cursor.execute(PSQL, args[0])
                except ValueError:
                    cursor.execute(PSQL, tuple(args[0]))
                except:
                    print(sys._getframe().f_back.f_code)
                    print(sys._getframe().f_back.f_code.co_name)
                    traceback.print_exc()
                    return ()
                finally:
                    return cursor.close()