【问题标题】:django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread - with celery beat and dbbackupdjango.db.utils.DatabaseError:在线程中创建的 DatabaseWrapper 对象只能在同一个线程中使用 - 使用 celery beat 和 dbbackup
【发布时间】:2020-07-25 17:34:47
【问题描述】:

我正在编写一个代码来频繁地将我们的数据库备份到 Dropbox。以下是我的tasks.py,它有一个测试代码,可以每 1 分钟执行一次 Django 管理命令management.call_command('dbbackup', interactive=False)。但是我遇到了错误django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 140423029811616 and this is thread id 140422957233632.

tasks.py

from __future__ import absolute_import, unicode_literals

from myproject.celery import app
from celery.utils.log import get_task_logger

from celery.schedules import crontab
from django.core import management

@app.task
def db_backup_to_dropbox():
    management.call_command('dbbackup', interactive=False)

app.conf.beat_schedule = {
    'backup-every-second': {
        'task': 'core.tasks.db_backup_to_dropbox',
        'schedule': crontab(minute='*/1'),
        'args': (),
    },
}

来自 celery.log 的回溯

[2020-07-25 16:24:00,050: INFO/MainProcess] Received task: core.tasks.db_backup_to_dropbox[a34653fe-a3c6-4259-a98d-7613c5f3446c]
[2020-07-25 16:24:00,054: INFO/MainProcess] Backing Up Database: myproject
[2020-07-25 16:24:00,213: INFO/MainProcess] Writing file to default-myserver-loc1-2020-07-25-162400.dump
[2020-07-25 16:24:00,215: INFO/MainProcess] Request to files/get_metadata
[2020-07-25 16:24:00,287: ERROR/MainProcess] RecursionError: maximum recursion depth exceeded while calling a Python object
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/utils.py", line 118, in wrapper
    func(*args, **kwargs)
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/management/commands/dbbackup.py", line 61, in handle
    self._save_new_backup(database)
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/management/commands/dbbackup.py", line 88, in _save_new_backup
    self.write_to_storage(outputfile, filename)
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/management/commands/_base.py", line 88, in write_to_storage
    self.storage.write_file(file, path)
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/storage.py", line 82, in write_file
    self.storage.save(name=filename, content=filehandle)
  File "/myproject/venv/lib/python3.8/site-packages/django/core/files/storage.py", line 51, in save
    name = self.get_available_name(name, max_length=max_length)
  File "/myproject/venv/lib/python3.8/site-packages/django/core/files/storage.py", line 82, in get_available_name
    while self.exists(name) or (max_length and len(name) > max_length):
  File "/myproject/venv/lib/python3.8/site-packages/storages/backends/dropbox.py", line 93, in exists
    return bool(self.client.files_get_metadata(self._full_path(name)))
  File "/myproject/venv/lib/python3.8/site-packages/dropbox/base.py", line 1682, in files_get_metadata
    r = self.request(
  File "/myproject/venv/lib/python3.8/site-packages/dropbox/dropbox.py", line 313, in request
    res = self.request_json_string_with_retry(host,
  File "/myproject/venv/lib/python3.8/site-packages/dropbox/dropbox.py", line 463, in request_json_string_with_retry
    return self.request_json_string(host,
  File "/myproject/venv/lib/python3.8/site-packages/dropbox/dropbox.py", line 559, in request_json_string
    r = self._session.post(url,
  File "/myproject/venv/lib/python3.8/site-packages/requests/sessions.py", line 578, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "/myproject/venv/lib/python3.8/site-packages/requests/sessions.py", line 530, in request
    resp = self.send(prep, **send_kwargs)
  File "/myproject/venv/lib/python3.8/site-packages/requests/sessions.py", line 643, in send
    r = adapter.send(request, **kwargs)
  File "/myproject/venv/lib/python3.8/site-packages/requests/adapters.py", line 439, in send
    resp = conn.urlopen(
  File "/myproject/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 670, in urlopen    httplib_response = self._make_request(
  File "/myproject/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 381, in _make_request
    self._validate_conn(conn)
  File "/myproject/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 978, in _validate_conn
    conn.connect()
  File "/myproject/venv/lib/python3.8/site-packages/urllib3/connection.py", line 343, in connect
    self.ssl_context = create_urllib3_context(
  File "/myproject/venv/lib/python3.8/site-packages/urllib3/util/ssl_.py", line 277, in create_urllib3_context
    context.options |= options
  File "/usr/lib/python3.8/ssl.py", line 602, in options
    super(SSLContext, SSLContext).options.__set__(self, value)
  File "/usr/lib/python3.8/ssl.py", line 602, in options
    super(SSLContext, SSLContext).options.__set__(self, value)
  File "/usr/lib/python3.8/ssl.py", line 602, in options
    super(SSLContext, SSLContext).options.__set__(self, value)
  [Previous line repeated 460 more times]

[2020-07-25 16:24:00,325: ERROR/MainProcess] Task core.tasks.db_backup_to_dropbox[a34653fe-a3c6-4259-a98d-7613c5f3446c] raised unexpected: DatabaseError("DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 140423029811616 and this is thread id 140422957233632.")
Traceback (most recent call last):
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/utils.py", line 118, in wrapper
    func(*args, **kwargs)
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/management/commands/dbbackup.py", line 61, in handle
    self._save_new_backup(database)
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/management/commands/dbbackup.py", line 88, in _save_new_backup
    self.write_to_storage(outputfile, filename)
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/management/commands/_base.py", line 88, in write_to_storage
    self.storage.write_file(file, path)
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/storage.py", line 82, in write_file
    self.storage.save(name=filename, content=filehandle)
  File "/myproject/venv/lib/python3.8/site-packages/django/core/files/storage.py", line 51, in save
    name = self.get_available_name(name, max_length=max_length)
  File "/myproject/venv/lib/python3.8/site-packages/django/core/files/storage.py", line 82, in get_available_name
    while self.exists(name) or (max_length and len(name) > max_length):
  File "/myproject/venv/lib/python3.8/site-packages/storages/backends/dropbox.py", line 93, in exists
    return bool(self.client.files_get_metadata(self._full_path(name)))
  File "/myproject/venv/lib/python3.8/site-packages/dropbox/base.py", line 1682, in files_get_metadata
    r = self.request(
  File "/myproject/venv/lib/python3.8/site-packages/dropbox/dropbox.py", line 313, in request
    res = self.request_json_string_with_retry(host,
  File "/myproject/venv/lib/python3.8/site-packages/dropbox/dropbox.py", line 463, in request_json_string_with_retry
    return self.request_json_string(host,
  File "/myproject/venv/lib/python3.8/site-packages/dropbox/dropbox.py", line 559, in request_json_string
    r = self._session.post(url,
  File "/myproject/venv/lib/python3.8/site-packages/requests/sessions.py", line 578, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "/myproject/venv/lib/python3.8/site-packages/requests/sessions.py", line 530, in request
    resp = self.send(prep, **send_kwargs)
  File "/myproject/venv/lib/python3.8/site-packages/requests/sessions.py", line 643, in send
    r = adapter.send(request, **kwargs)
  File "/myproject/venv/lib/python3.8/site-packages/requests/adapters.py", line 439, in send
    resp = conn.urlopen(
  File "/myproject/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 670, in urlopen    httplib_response = self._make_request(
  File "/myproject/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 381, in _make_request
    self._validate_conn(conn)
  File "/myproject/venv/lib/python3.8/site-packages/urllib3/connectionpool.py", line 978, in _validate_conn
    conn.connect()
  File "/myproject/venv/lib/python3.8/site-packages/urllib3/connection.py", line 343, in connect
    self.ssl_context = create_urllib3_context(
  File "/myproject/venv/lib/python3.8/site-packages/urllib3/util/ssl_.py", line 277, in create_urllib3_context
    context.options |= options
  File "/usr/lib/python3.8/ssl.py", line 602, in options
    super(SSLContext, SSLContext).options.__set__(self, value)
  File "/usr/lib/python3.8/ssl.py", line 602, in options
    super(SSLContext, SSLContext).options.__set__(self, value)
  File "/usr/lib/python3.8/ssl.py", line 602, in options
    super(SSLContext, SSLContext).options.__set__(self, value)
  [Previous line repeated 460 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/myproject/venv/lib/python3.8/site-packages/celery/app/trace.py", line 412, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/myproject/venv/lib/python3.8/site-packages/celery/app/trace.py", line 704, in __protected_call__
    return self.run(*args, **kwargs)
  File "/myproject/myproject/core/tasks.py", line 11, in db_backup_to_dropbox
    management.call_command('dbbackup', interactive=False)
  File "/myproject/venv/lib/python3.8/site-packages/django/core/management/__init__.py", line 168, in call_command
    return command.execute(*args, **defaults)
  File "/myproject/venv/lib/python3.8/site-packages/django/core/management/base.py", line 369, in execute
    output = self.handle(*args, **options)
  File "/myproject/venv/lib/python3.8/site-packages/dbbackup/utils.py", line 127, in wrapper
    connection.close()
  File "/myproject/venv/lib/python3.8/site-packages/django/utils/asyncio.py", line 26, in inner
    return func(*args, **kwargs)
  File "/myproject/venv/lib/python3.8/site-packages/django/db/backends/base/base.py", line 286, in close
    self.validate_thread_sharing()
  File "/myproject/venv/lib/python3.8/site-packages/django/db/backends/base/base.py", line 553, in validate_thread_sharing
    raise DatabaseError(
django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 140423029811616 and this is thread id 140422957233632.

【问题讨论】:

    标签: python django multithreading celery celerybeat


    【解决方案1】:

    尝试在 setting.py 中添加这些行

    CELERY_TASK_ALWAYS_EAGER = 真

    【讨论】:

    • 您好,您能否描述一下它是如何以及为什么起作用的?这将有助于其他访问该帖子的人了解您的建议如何解决问题。谢谢
    • 文档说,“也就是说,任务将在本地执行,而不是发送到队列中。”这也会影响所有其他任务。我想知道我的代码出了什么问题以及如何解决它而不必在本地运行它们。
    猜你喜欢
    • 1970-01-01
    • 2018-06-21
    • 2020-09-12
    • 2020-05-22
    • 2017-03-01
    • 2019-10-21
    • 2021-09-20
    • 2021-01-16
    • 2019-10-30
    相关资源
    最近更新 更多