読者です 読者をやめる 読者になる 読者になる

cx_Oracleをマルチスレッドで使う

Python Django OracleDatabase

PythonOracle Databaseに接続するには、cx_Oracleを使う。
マルチスレッド環境下でcx_Oracleを使う場合にハマったのでメモを残す。
Oracleのクライアントライブラリは、マルチスレッドで使う際には、OCI_THREADEDというモードで使わないといけないらしい。
cx_OracleをOCI_THREADEDモードで使うには、connect関数のthreadedオプションにTrueを指定する。

>>> import cx_Oracle
>>> connection = cx_Oracle.connect(
...     "testuser",
...     "testpassword",
...     "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=oracledb.example.com) (PORT=1521))(CONNECT_DATA=(SID=ORCL)))",
...     threaded=True)

cx_Oracleのドキュメントにも説明があった。

The threaded argument is expected to be a boolean expression which indicates whether or not Oracle should use the mode OCI_THREADED to wrap accesses to connections with a mutex.
Doing so in single threaded applications imposes a performance penalty of about 10-15% which is why the default is False.

Module Interface — cx_Oracle 5.2.1 documentation

DjangoOracleを使っていて、マルチスレッドで動作させる場合だと、settingsのデータベース設定に指定すればよい。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.oracle',
        'NAME': 'oracledb.example.com:1521/orcl',
        'USER': 'testuser',
        'PASSWORD': 'testpassword',
        'OPTIONS': {
            'threaded': True,
        }
    }
}

この指定をしない状態で、gunicornのThreadWorkerで動かしていた際に、低頻度でワーカープロセスがログを出力せずに死ぬ、という現象が発生していた。
シングルスレッドの場合は、threaded=Falseのほうがパフォーマンスが良いそうなので、使いどころに気をつけたい。