Repository: deepset-ai/haystack

Issue:
FAISS documentstore giving IndexFlat error after 100 api requests
**Describe the bug**
I have created an Extractive QA pipeline prediction API and trying to test the predictions in API. I am not getting any issues while building a docker container and the app works perfectly fine when I test with a few queries. But I am getting the following Index error after sending 100 requests to the app. What could be the issue if it's failing after 100 requests and when I restarted the app it's again working till 100 requests?

**Error message**
ERROR:main:Exception on /predict_qa_extract [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/flask/app.py", line 2525, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.7/dist-packages/flask/app.py", line 1822, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.7/dist-packages/flask_cors/extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/usr/local/lib/python3.7/dist-packages/flask/app.py", line 1820, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.7/dist-packages/flask/app.py", line 1796, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/usr/src/app/main.py", line 54, in predict_api_extract
    prediction = pipe_extractive.run(query= input_query, params={"Retriever": {"top_k": 10}, "Reader": {"top_k": 3}})
  File "/usr/local/lib/python3.7/dist-packages/haystack/pipelines/standard_pipelines.py", line 338, in run
    output = self.pipeline.run(query=query, params=params, debug=debug)
  File "/usr/local/lib/python3.7/dist-packages/haystack/pipelines/base.py", line 575, in run
    self.send_pipeline_event_if_needed(is_indexing=file_paths is not None)
  File "/usr/local/lib/python3.7/dist-packages/haystack/pipelines/base.py", line 2266, in send_pipeline_event_if_needed
    self.send_pipeline_event(is_indexing)
  File "/usr/local/lib/python3.7/dist-packages/haystack/pipelines/base.py", line 2248, in send_pipeline_event
    fingerprint = sha1(json.dumps(self.get_config(), sort_keys=True).encode()).hexdigest()
  File "/usr/lib/python3.7/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/usr/lib/python3.7/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.7/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python3.7/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type IndexFlat is not JSON serializable

**Additional context**
I am using FAISS documentstore with DPR and FARM reader. Also, I am saving the document store after updating embeddings separately and loading it in the API with the following commands.
document_store.save(index_path="content_index.faiss", config_path="content_config.json")

document_store2 = FAISSDocumentStore.load(index_path="content_index.faiss", config_path="content_config.json")

Let me know if you need more information.

**System:**
 - OS: LINUX
 - GPU/CPU: GPU
 - Haystack version (commit or version number):  1.11.1
 - DocumentStore: FAISS
 - Reader: FARM
 - Retriever: DPR



Discussion:

Resolving patch:
diff --git a/haystack/pipelines/base.py b/haystack/pipelines/base.py
--- a/haystack/pipelines/base.py
+++ b/haystack/pipelines/base.py
@@ -2288,7 +2288,8 @@ def uptime(self) -> timedelta:
         return datetime.datetime.now(datetime.timezone.utc) - self.init_time
 
     def send_pipeline_event(self, is_indexing: bool = False):
-        fingerprint = sha1(json.dumps(self.get_config(), sort_keys=True).encode()).hexdigest()
+        json_repr = json.dumps(self.get_config(), sort_keys=True, default=lambda o: "<not serializable>")
+        fingerprint = sha1(json_repr.encode()).hexdigest()
         send_custom_event(
             "pipeline",
             payload={


Test patch:
diff --git a/test/pipelines/test_pipeline.py b/test/pipelines/test_pipeline.py
--- a/test/pipelines/test_pipeline.py
+++ b/test/pipelines/test_pipeline.py
@@ -1,19 +1,17 @@
-from copy import deepcopy
-from pathlib import Path
-import os
 import ssl
 import json
 import platform
 import sys
+import datetime
 from typing import Tuple
+from copy import deepcopy
+from unittest import mock
 
 import pytest
 from requests import PreparedRequest
 import responses
 import logging
-from transformers import pipeline
 import yaml
-import pandas as pd
 
 from haystack import __version__
 from haystack.document_stores.deepsetcloud import DeepsetCloudDocumentStore
@@ -36,16 +34,13 @@
     DocumentSearchPipeline,
     QuestionGenerationPipeline,
     MostSimilarDocumentsPipeline,
-    BaseStandardPipeline,
 )
 from haystack.pipelines.config import validate_config_strings, get_component_definitions
 from haystack.pipelines.utils import generate_code
 from haystack.errors import PipelineConfigError
-from haystack.nodes import PreProcessor, TextConverter, QuestionGenerator
+from haystack.nodes import PreProcessor, TextConverter
 from haystack.utils.deepsetcloud import DeepsetCloudError
-from haystack import Document, Answer
-from haystack.nodes.other.route_documents import RouteDocuments
-from haystack.nodes.other.join_answers import JoinAnswers
+from haystack import Answer
 
 from ..conftest import (
     MOCK_DC,
@@ -2158,3 +2153,44 @@ def test_fix_to_pipeline_execution_when_join_follows_join():
     res = pipeline.run(query="Alpha Beta Gamma Delta")
     documents = res["documents"]
     assert len(documents) == 4  # all four documents should be found
+
+
+def test_send_pipeline_event():
+    """
+    Test the event can be sent and the internal fields are correctly set
+    """
+    pipeline = Pipeline()
+    pipeline.add_node(MockNode(), name="mock_node", inputs=["Query"])
+
+    with mock.patch("haystack.pipelines.base.send_custom_event") as mocked_send:
+        today_at_midnight = datetime.datetime.combine(datetime.datetime.now(), datetime.time.min, datetime.timezone.utc)
+        pipeline.send_pipeline_event()
+        mocked_send.assert_called_once()
+        assert pipeline.time_of_last_sent_event == today_at_midnight
+        assert pipeline.last_window_run_total == 0
+
+
+def test_send_pipeline_event_unserializable_param():
+    """
+    Test the event can be sent even when a certain component was initialized with a
+    non-serializable parameter, see https://github.com/deepset-ai/haystack/issues/3833
+    """
+
+    class CustomNode(MockNode):
+        """A mock node that can be inited passing a param"""
+
+        def __init__(self, param):
+            self.param = param
+
+    # create a custom node passing a parameter that can't be serialized (an empty set)
+    custom_node = CustomNode(param=set())
+
+    pipeline = Pipeline()
+    pipeline.add_node(custom_node, name="custom_node", inputs=["Query"])
+
+    with mock.patch("haystack.pipelines.base.send_custom_event") as mocked_send:
+        today_at_midnight = datetime.datetime.combine(datetime.datetime.now(), datetime.time.min, datetime.timezone.utc)
+        pipeline.send_pipeline_event()
+        mocked_send.assert_called_once()
+        assert pipeline.time_of_last_sent_event == today_at_midnight
+        assert pipeline.last_window_run_total == 0