使用Django-Haystack和ElasticSearch捕获ConnectionError

时间:2014-11-11 12:41:58

标签: python django elasticsearch django-haystack

我目前在项目中使用django-haystack和elasticsearch,并且当弹性搜索运行时,所有工作都按预期工作。

干草堆设置:

HAYSTACK_CONNECTIONS = {
'default': {
    'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
    'URL': 'http://127.0.0.1:9200/',
    'INDEX_NAME': 'haystack',
},
}

HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

我正在使用 RealtimeSignalProcessor 进行实时索引更新。

当elasticsearch关闭时会出现问题,因为尝试添加/更新任何对象会给我们带来以下错误:

ConnectionError(('Connection aborted.', error(111, 'Connection refused'))) caused by: ProtocolError(('Connection aborted.', error(111, 'Connection refused')))

有没有办法捕捉/管理这个错误?

它在生产环境中非常有用,以便在弹性搜索停止时允许用户添加/更新对象而不会崩溃。

提前致谢。

2 个答案:

答案 0 :(得分:4)

我建议您继承ElasticSearchBackend并将updateremoveclear方法包装在捕获异常的装饰器周围。这样你就可以保留elasticsearch功能,但是你可以覆盖它们的行为。

我用它来装饰一个装饰器,一个静音错误:

def mute_error(f):      
    def error_wrapper(*args, **kwargs):  
        try:  
            return f(*args, **kwargs)  
        except:
            print('Connection Error')    

    return error_wrapper

然后将其添加到您的项目中,配置HAYSTACK_BACKEND

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
        'URL': 'http://127.0.0.1:9200/',
        'INDEX_NAME': 'haystack',
    },
    'robust_elasticsearch':{
        'ENGINE': 'YOURAPP.backend.RobustElasticSearchEngine',
        'URL': 'http://127.0.0.1:9200/',
        'INDEX_NAME': 'haystack',
    }
}

查看django-haystack文档。您还应该创建一个BaseEngine的子类,这没有正确记录。

这是代码:

from django.utils.decorators import method_decorator
from haystack.backends.elasticsearch_backend import ElasticsearchSearchBackend, ElasticsearchSearchEngine
from haystack.backends import BaseEngine
from haystack.backends import log_query
from urllib3.exceptions import ProtocolError, ConnectionError


class RobustElasticSearchBackend(ElasticsearchSearchBackend):
    """A robust backend that doesn't crash when no connection is available"""

    def mute_error(f):

        def error_wrapper(self, *args, **kwargs):
            try:
                return f(self, *args, **kwargs)
            except TransportError:
                self.log.warn('Connection Error: elasticsearch communication error') 
        return error_wrapper

    def __init__(self, connectionalias, **options):
        super(RobustElasticSearchBackend, self).__init__(connectionalias, **options)

    @mute_error
    def update(self, indexer, iterable, commit=True):
        super(RobustElasticSearchBackend, self).update(indexer, iterable, commit)

    @mute_error
    def remove(self, obj, commit=True):
        super(RobustElasticSearchBackend, self).remove(obj, commit)

    @mute_error
    def clear(self, models=[], commit=True):
        super(RobustElasticSearchBackend, self).clear(models, commit)

class RobustElasticSearchEngine(ElasticsearchSearchEngine):
    backend = RobustElasticSearchBackend

我们只是重写引擎,而不是SearchQuery子类,因为默认情况下弹性搜索类提供的子类对我们来说已经足够了。

答案 1 :(得分:1)

为了让我的设置工作,我必须

import elasticsearch

并编辑为:

def mute_error(f):

    def error_wrapper(self, *args, **kwargs):
        try:
            return f(self, *args, **kwargs)
        except elasticsearch.TransportError:
            self.log.warn('Connection Error: elasticsearch communication error')
    return error_wrapper