【问题标题】:Python cassandra-driver OperationTimeOut on every query in Celery task芹菜任务中每个查询的Python cassandra-driver OperationTimeOut
【发布时间】:2014-07-16 15:54:12
【问题描述】:

我对在 celery 任务中异步执行的每个插入查询(小查询)都有问题。 在同步模式下,当我确实插入时一切都做得很好,但是当它在 apply_async() 中执行时,我得到了这个:

OperationTimedOut('errors=errors=errors={}, last_host=***.***.*.***, last_host=None, last_host=None',)

追溯:

Traceback (most recent call last):
  File "/var/nfs_www/***/env_v0/local/lib/python2.7/site-packages/celery/app/trace.py", line 240, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/var/nfs_www/***/env_v0/local/lib/python2.7/site-packages/celery/app/trace.py", line 437, in __protected_call__
    return self.run(*args, **kwargs)
  File "/var/nfs_www/***/www_v1/app/mods/news_feed/tasks.py", line 26, in send_new_comment_reply_notifications
    send_new_comment_reply_notifications_method(comment_id)
  File "/var/nfs_www/***www_v1/app/mods/news_feed/methods.py", line 83, in send_new_comment_reply_notifications
    comment_type='comment_reply'
  File "/var/nfs_www/***/www_v1/app/mods/news_feed/models/storage.py", line 129, in add
    CommentsFeed(**kwargs).save()
  File "/var/nfs_www/***/env_v0/local/lib/python2.7/site-packages/cqlengine/models.py", line 531, in save
    consistency=self.__consistency__).save()
  File "/var/nfs_www/***/env_v0/local/lib/python2.7/site-packages/cqlengine/query.py", line 907, in save
    self._execute(insert)
  File "/var/nfs_www/***/env_v0/local/lib/python2.7/site-packages/cqlengine/query.py", line 786, in _execute
    tmp = execute(q, consistency_level=self._consistency)
  File "/var/nfs_www/***/env_v0/local/lib/python2.7/site-packages/cqlengine/connection.py", line 95, in execute
    result = session.execute(query, params)
  File "/var/nfs_www/***/env_v0/local/lib/python2.7/site-packages/cassandra/cluster.py", line 1103, in execute
    result = future.result(timeout)
  File "/var/nfs_www/***/env_v0/local/lib/python2.7/site-packages/cassandra/cluster.py", line 2475, in result
    raise OperationTimedOut(errors=self._errors, last_host=self._current_host)
OperationTimedOut: errors={}, last_host=***.***.*.***

有人对问题有想法吗?

我找到了这个When cassandra-driver was executing the query, cassandra-driver returned error OperationTimedOut,但我的查询很少,而且只在 celery 任务中出现问题。

更新:

我做了一个测试任务,它也引发了这个错误。

@celery.task()
def test_task_with_cassandra():
    from app import cassandra_session
    cassandra_session.execute('use news_feed')
    return 'Done'

更新 2: 做了这个:

@celery.task()
def test_task_with_cassandra():
    from cqlengine import connection
    connection.setup(app.config['CASSANDRA_SERVERS'], port=app.config['CASSANDRA_PORT'],
                     default_keyspace='test_keyspace')
    from .models import Feed
    Feed.objects.count()
    return 'Done'

知道了:

NoHostAvailable('Unable to connect to any servers', {'***.***.*.***': OperationTimedOut('errors=errors=Timed out creating connection, last_host=None, last_host=None',)})

我可以从 shell 连接到它

更新 3: 从 github 问题上的已删除线程(在我的电子邮件中找到):(这对我也有用) 以下是我将 CQLengine 插入 Celery 的方法:

from celery import Celery
from celery.signals import worker_process_init, beat_init
from cqlengine import connection
from cqlengine.connection import (
    cluster as cql_cluster, session as cql_session)

def cassandra_init():
    """ Initialize a clean Cassandra connection. """
    if cql_cluster is not None:
        cql_cluster.shutdown()
    if cql_session is not None:
        cql_session.shutdown()
    connection.setup()

# Initialize worker context for both standard and periodic tasks.
worker_process_init.connect(cassandra_init)
beat_init.connect(cassandra_init)

app = Celery()

这是粗略的,但有效。我们应该在 FAQ 中添加这个 sn-p 吗?

【问题讨论】:

  • 您的 celery 用户是否有权运行查询?
  • 嗯,我没有为它设置任何身份验证提供程序。或者你是什么意思?我应该在哪里搜索?我已经更新了我的问题。
  • 你解决了吗?我遇到了同样的问题,不知道发生了什么!
  • @haifzhan, 特别为你添加 raritet 信息 :))) 见更新 3
  • 感谢您发布@EllochkaCannibal,我检查了我的脚本,发现如果多处理进程共享一个会话,它会引发 OperationTimedOut 异常,在我为每个进程创建一个会话后,问题解决了。

标签: python cassandra celery cqlengine


【解决方案1】:

受 Ron 回答的启发,我想出了以下代码放入 tasks.py:

import threading
from django.conf import settings
from cassandra.cluster import Cluster
from celery.signals import worker_process_init,worker_process_shutdown

thread_local = threading.local()

@worker_process_init.connect
def open_cassandra_session(*args, **kwargs):
    cluster = Cluster([settings.DATABASES["cassandra"]["HOST"],], protocol_version=3)
    session = cluster.connect(settings.DATABASES["cassandra"]["NAME"])
    thread_local.cassandra_session = session

@worker_process_shutdown.connect
def close_cassandra_session(*args,**kwargs):
    session = thread_local.cassandra_session
    session.shutdown()
    thread_local.cassandra_session = None

这个简洁的解决方案将在 celery 工作进程启动和停止时自动打开/关闭 cassandra 会话。

旁注:protocol_version=3,因为 Cassandra 2.1 仅支持协议版本 3 及更低版本。

【讨论】:

  • 我赞成这个答案,但我改变了主意——这实际上对我不起作用。我发布了一个不同的答案。
【解决方案2】:

我遇到了类似的问题。它似乎与在任务之间共享 Cassandra 会话有关。我通过为每个线程创建一个会话来解决它。确保从您的任务中调用get_session(),然后执行以下操作:

thread_local = threading.local()

def get_session():
    if hasattr(thread_local, "cassandra_session"):
        return thread_local.cassandra_session

    cluster = Cluster(settings.CASSANDRA_HOSTS)
    session = cluster.connect(settings.CASSANDRA_KEYSPACE)

    thread_local.cassandra_session = session

    return session

【讨论】:

    【解决方案3】:

    其他答案对我不起作用,但问题的“更新 3”对我有用。这是我最终得到的结果(问题中建议的小更新):

    from celery.signals import worker_process_init
    from cassandra.cqlengine import connection
    from cassandra.cqlengine.connection import (
        cluster as cql_cluster, session as cql_session)
    
    def cassandra_init(*args, **kwargs):
        """ Initialize a clean Cassandra connection. """
        if cql_cluster is not None:
            cql_cluster.shutdown()
        if cql_session is not None:
            cql_session.shutdown()
        connection.setup(settings.DATABASES["cassandra"]["HOST"].split(','), settings.DATABASES["cassandra"]["NAME"])
    
    # Initialize worker context (only standard tasks)
    worker_process_init.connect(cassandra_init)
    

    【讨论】:

    • 你拯救了我的一天,我的朋友
    • 你又为另一个朋友节省了一天...谢谢。
    【解决方案4】:

    使用 django-cassandra-engine 以下解决了我的问题:

    db_connection = connections['cassandra']
    
    @worker_process_init.connect
    def connect_db(**_):
        db_connection.reconnect()
    
    
    @worker_shutdown.connect
    def disconnect(**_):
        db_connection.connection.close_all()
    

    here

    【讨论】:

      猜你喜欢
      • 2020-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-28
      • 1970-01-01
      • 1970-01-01
      • 2016-03-22
      • 2014-12-04
      相关资源
      最近更新 更多