'sqlalchemy pyodbc connect() fails without setting exception

When I run fastapi/pyodbc to connect MSSQL, unicorn server crashes frequently when connect to sqlalchemy fails (sometimes not everytime). I have noticed specifically with nullpool class is used while creating engine.

Here is the sqlalchemy error: SystemError: returned NULL without setting an exception

I use gunicorn to run unicorn, so whenever unicorn crashes with sqlalchemy issue...unicorn server crashes and gunicorn restart the worker thread.

In the code, I connect to remote SQL Server using pyodbc. I use sqlalchemy as ORM.

Seems like db connect method is failing and it is not setting an exception. So try catch is not executing EXCEPT code correctly. So, python crashes. Eventually unicorn is crashing.

Here is the unicorn crash message:

[2771] [WARNING] Worker with pid 2773 was terminated due to signal 11 <br>
[2852] [INFO] Booting worker with pid: 2852

sqlalchemy, python 3.10.2, pyodbc, gunicorn, unicorn - all are latest releases/versions.

Here is the code:

    def get_sqlserver_info(self):
        host_names: list = []
        if self.gg_details.get('groups'):
            for g_idx, g_group in enumerate(self.gg_details['groups']):
                if g_group.get('dsn_host_name'):
                    if g_group['dsn_host_name'].upper() not in [i.upper() for i in host_names]:
                        host_names.append(g_group['dsn_host_name'])

        password: str = ''
        if self.target_dbinst_connect_mode == 'sql':
            password = get_password(account_type='sql', domain='', login_user='', default_svc_acct='Y')
        for host_name in host_names:
            if self.target_dbinst_connect_mode == 'windows':
                connection_url = URL.create(
                    "mssql+pyodbc",
                    host=host_name,
                    port=1433,
                    database="master",
                    query={
                        "driver": "ODBC Driver 17 for SQL Server",
                        "authentication": "ActiveDirectoryIntegrated",
                        "TrustServerCertificate": "Yes",
                        "MARS_Connection": "Yes",
                    },
                )
            elif self.target_dbinst_connect_mode == 'sql':
                connection_url = URL.create(
                    "mssql+pyodbc",
                    username='sql_user',
                    password=password,
                    host=host_name,
                    port=1433,
                    database="master",
                    query={
                        "driver": "ODBC Driver 17 for SQL Server",
                        "MARS_Connection": "Yes",
                    },
                )

            g_mssql_def_isolation_level = "READ COMMITTED"
            g_mssql_RU_isolation_level = "READ UNCOMMITTED"
            l_connect_args = {
                "timeout": 20,
                "encoding": "utf8"
            }
            r_engine = create_engine(connection_url, echo=False, future=True, query_cache_size=1200,
                                     connect_args=l_connect_args, poolclass=NullPool)
            # get agent job information
            try:
                dbconn = r_engine.connect().execution_options(isolation_level=g_mssql_RU_isolation_level)
                # p = Path(Path.cwd() / 'mm/DBUtility/sql_scripts/gg/SQLJobStatus.sql').resolve()
                p = Path(__file__).parent.parent.absolute() / 'sql_scripts/gg/SQLJobStatus.sql'
                sql = Path(p).read_text()
                stmt = text(sql)
                result = dbconn.execute(stmt)
                dbconn.close()
            except exc.IntegrityError as e:
                print(f'{host_name} - Integrity error raised', '\n', str(e))
            except exc.SQLAlchemyError as e:
                print(f'Could not connect to {host_name}. Func: get_sqlserver_info - Something went wrong', '\n',
                      str(e))

            # get database version
            try:
                dbconn = r_engine.connect().execution_options(isolation_level=g_mssql_RU_isolation_level)
                sql = """\
                SELECT @@version as db_version
                """
                stmt = text(sql)
                result = dbconn.execute(stmt)
                dbconn.close()
            except exc.IntegrityError as e:
                print(f'{host_name} - Integrity error raised', '\n', str(e))
            except exc.SQLAlchemyError as e:
                print(f'Could not connect to {host_name}. Func: get_sqlserver_info - Something went wrong', '\n',
                      str(e))

            r_engine.dispose()

Here is error message

ERROR:apscheduler.executors.default:Job "Job Name (trigger: interval[0:00:10], next run at: 2022-01-23 15:01:28 EST)" raised an exception

Traceback (most recent call last): <br>
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/apscheduler/executors/base.py", line 125, in run_job
    retval = job.func(*job.args, **job.kwargs)
  File "/home/sqlserver/MMProj/mm/Config/services/APSchService.py", line 30, in run_job
    apsch.gg_monitor(p_job)
  File "/home/sqlserver/MMProj/mm/Config/services/APSchService.py", line 51, in gg_monitor
    ps_status_code, error_msg, outlst = gg.run_ggcmds_using_winrm(
  File "/home/sqlserver/MMProj/mm/DBUtility/services/GGMonitor19Service.py", line 2172, in run_ggcmds_using_winrm
    self.get_sqlserver_info()
  File "/home/sqlserver/MMProj/mm/DBUtility/services/GGMonitor19Service.py", line 1603, in get_sqlserver_info
    dbconn = r_engine.connect().execution_options(isolation_level=g_mssql_RU_isolation_level)
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/future/engine.py", line 406, in connect
    return super(Engine, self).connect()
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3204, in connect
    return self._connection_cls(self, close_with_result=close_with_result)
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 96, in __init__
    else engine.raw_connection()
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3283, in raw_connection
    return self._wrap_pool_connect(self.pool.connect, _connection)
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3250, in _wrap_pool_connect
    return fn()
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 310, in connect
    return _ConnectionFairy._checkout(self)
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 868, in _checkout
    fairy = _ConnectionRecord.checkout(pool)
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 476, in checkout
    rec = pool._do_get()
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/pool/impl.py", line 145, in _do_get
    with util.safe_reraise():
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__
    compat.raise_(
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/pool/impl.py", line 143, in _do_get
    return self._create_connection()
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 256, in _create_connection
    return _ConnectionRecord(self)
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 371, in __init__
    self.__connect()
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 665, in __connect
    with util.safe_reraise():
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__
    compat.raise_(
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 661, in __connect
    self.dbapi_connection = connection = pool._invoke_creator(self)
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/engine/create.py", line 590, in connect
    return dialect.connect(*cargs, **cparams)
  File "/home/sqlserver/MMProj/venv/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 597, in connect
    return self.dbapi.connect(*cargs, **cparams) <br>
SystemError: <built-in function connect> returned NULL without setting an exception


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source