diff --git a/wagtail/search/backends/base.py b/wagtail/search/backends/base.py index 9e73f1199b..ae27ab7fd8 100644 --- a/wagtail/search/backends/base.py +++ b/wagtail/search/backends/base.py @@ -299,6 +299,7 @@ class BaseSearchBackend: autocomplete_query_compiler_class = None results_class = None rebuilder_class = None + catch_indexing_errors = False def __init__(self, params): pass diff --git a/wagtail/search/backends/elasticsearch2.py b/wagtail/search/backends/elasticsearch2.py index da42a7f3e5..57381ec392 100644 --- a/wagtail/search/backends/elasticsearch2.py +++ b/wagtail/search/backends/elasticsearch2.py @@ -1006,6 +1006,7 @@ class Elasticsearch2SearchBackend(BaseSearchBackend): mapping_class = Elasticsearch2Mapping basic_rebuilder_class = ElasticsearchIndexRebuilder atomic_rebuilder_class = ElasticsearchAtomicIndexRebuilder + catch_indexing_errors = True settings = { 'settings': { diff --git a/wagtail/search/index.py b/wagtail/search/index.py index a0e70fac28..bb779f73c2 100644 --- a/wagtail/search/index.py +++ b/wagtail/search/index.py @@ -154,9 +154,19 @@ def insert_or_update_object(instance): try: backend.add(indexed_instance) except Exception: - # Catch and log all errors + # Log all errors logger.exception("Exception raised while adding %r into the '%s' search backend", indexed_instance, backend_name) + # Catch exceptions for backends that use an external service like Elasticsearch + # This is to prevent data loss if that external service was to go down and the user's + # save request was to fail. + # But note that we don't want this for database backends though as an error during a + # database transaction will require the transaction to be rolled back anyway. So If + # we caught the error here, the request will only crash again when the next database + # query is made but then the error message wouldn't be very informative. + if not backend.catch_indexing_errors: + raise + def remove_object(instance): indexed_instance = get_indexed_instance(instance, check_exists=False) @@ -166,9 +176,14 @@ def remove_object(instance): try: backend.delete(indexed_instance) except Exception: - # Catch and log all errors + # Log all errors logger.exception("Exception raised while deleting %r from the '%s' search backend", indexed_instance, backend_name) + # Only catch the exception if the backend requires this + # See the comments in insert_or_update_object for an explanation + if not backend.catch_indexing_errors: + raise + class BaseField: def __init__(self, field_name, **kwargs):