簡體   English   中英

將 ThreadPoolExecutor 與 Django 一起使用時出現數據庫“正在被其他用戶訪問”錯誤

[英]Database “is being accessed by other users” error when using ThreadPoolExecutor with Django

我正在處理一個項目,我們解析一個有點大的文件並使用ThreadPoolExecutor異步處理每一行(我們為每一行調用 API)。 這曾經是同步完成的,我們有一個通過的測試套件。 然而,現在,當運行測試時,Django 的默認測試運行器在teardown_databases出錯:

Traceback (most recent call last):
  File "manage.py", line 34, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.5/site-packages/django/core/management/__init__.py", line 367, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.5/site-packages/django/core/management/__init__.py", line 359, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.5/site-packages/django/core/management/commands/test.py", line 29, in run_from_argv
    super(Command, self).run_from_argv(argv)
  File "/usr/local/lib/python3.5/site-packages/django/core/management/base.py", line 294, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.5/site-packages/django/core/management/base.py", line 345, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.5/site-packages/django/core/management/commands/test.py", line 72, in handle
    failures = test_runner.run_tests(test_labels)
  File "/usr/local/lib/python3.5/site-packages/django/test/runner.py", line 551, in run_tests
    self.teardown_databases(old_config)
  File "/usr/local/lib/python3.5/site-packages/django/test/runner.py", line 526, in teardown_databases
    connection.creation.destroy_test_db(old_name, self.verbosity, self.keepdb)
  File "/usr/local/lib/python3.5/site-packages/django/db/backends/base/creation.py", line 264, in destroy_test_db
    self._destroy_test_db(test_database_name, verbosity)
  File "/usr/local/lib/python3.5/site-packages/django/db/backends/base/creation.py", line 283, in _destroy_test_db
    % self.connection.ops.quote_name(test_database_name))
  File "/usr/local/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.5/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/usr/local/lib/python3.5/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/usr/local/lib/python3.5/site-packages/django/db/backends/utils.py", line 62, in execute
    return self.cursor.execute(sql)
django.db.utils.OperationalError: database "test_sftpm_db" is being accessed by other users
DETAIL:  There are 10 other sessions using the database.

(我們正在使用 10 個工人)

我嘗試在代碼中的許多地方手動關閉連接,但無濟於事。 有沒有正確的方法來解決這個問題?

確保在使用線程時在代碼中調用connection.close() 這為我解決了這個問題,其他建議的解決方案(測試方法的裝飾器,更改數據庫設置,數據庫功能,如上面 Nick 所示,重新啟動 postgres)沒有。 有用的例子

這看起來比 Postgres 更像是 Django 的問題——例如參見這張票: https : //code.djangoproject.com/ticket/22420

從您提供的內容來看,我看到 Django 在嘗試刪除它之前沒有關閉與測試數據庫的所有連接。 在這種情況下,Postges 嘗試保護其他會話免受數據丟失,因此在它們都斷開連接之前它無法刪除/重命名數據庫。

如果需要,您可以使用pg_terminate_backend(..)函數和pg_stat_activity視圖手動刪除測試數據庫:

select pg_terminate_backend(pid) 
from pg_stat_activity 
where
  datname = 'DATABASE_NAME'
;

drop database DATABASE_NAME;

如果由於某種原因,有人很快並且設法在這兩個命令之間進行連接,則drop database將再次失敗。 在這種情況下,您可以重復它,但在此之前撤銷從public連接到該數據庫的權限——這將阻止連接到它:

revoke connect on database DATABASE_NAME from public;

...然后重復上述操作。

我遇到了類似的問題並通過使用django.test.testcases.TransactionTestCase作為我的測試類的超類來解決它

與數據庫的連接是線程本地的。 我最終通過向執行程序返回的每個未來添加回調來解決這個問題。

from django.db import connections

def on_done(future):
    # Because each thread has a connection, so here you can call close_all() to close all connections under this thread name.
    connections.close_all()

def main():
    # ...
    with ThreadPoolExecutor() as executor:
        while True:
            future = executor.submit(do, get_a_job())
            future.add_done_callback(on_done)

在這里找到更多: https : //www.programmersought.com/article/3618244269/

另一個可能是問題的事情是您正在TestCase ,它對您的測試持有全局鎖。 子類化TransactionTestCase將解決此問題並允許您的測試可能產生的任何線程與數據庫進行通信

在我的PyCharm(運行進程)+ postgres db案例中,我通過運行修復了它:

1.以對db具有正確權限的用戶身份登錄,在我的情況下它是默認的“ postgres ”。

$ psql -h localhost -U postgres -W

2.然后使用命令刪除與現有數據庫的所有連接,在我的情況下為“ mydbname ”:

# select pg_terminate_backend(pid) from pg_stat_activity where datname='mydbname';

3.然后只需按正常方式單擊“運行”按鈕PyCharm。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM