Encountered the exception "Deserialization of document has failed" when creating documents using multithreading

Hi,

I have an import job that processes data from an Excel file to create documents. When I run the job using multithreading, I randomly encounter the following exception:

[WARN ][.support.internal.DefaultDocumentSupport][u:] - Deserialization of document has failed. Reason: For the entity instance '/FullPartTime[1]', the corresponding entity was not found in the corresponding document model. [ERROR,L0,s0,e0],

For the entity instance '/VacationFulltime[1]', the corresponding entity was not found in the corresponding document model. [ERROR,L0,s0,e0],
For the entity instance '/VacationParttime[1]', the corresponding entity was not found in the corresponding document model. [ERROR,L0,s0,e0],
For the entity instance '/WeekHoursHHMM[1]', the corresponding entity was not found in the corresponding document model. [ERROR,L0,s0,e0],

2024-11-21 05:05:52,242 [pool-5-thread-1     ][ERROR][ee.importdata.service.ExcelImportService][u:] - Failed to creating employee data for personalId: 4075
com.mgmtp.a12.dataservices.utils.internal.DocumentModelException: The validation of document of document model 'ContractHourAbsenceDM' failed. For the entity instance '/FullPartTime[1]', the corresponding entity was not found in the corresponding document model. [ERROR,L0,s0,e0],
For the entity instance '/VacationFulltime[1]', the corresponding entity was not found in the corresponding document model. [ERROR,L0,s0,e0],
For the entity instance '/VacationParttime[1]', the corresponding entity was not found in the corresponding document model. [ERROR,L0,s0,e0],

It happened randomly, If I re-import the same file, the exception is occurred for another document.
But if I execute in in one thread, it works fine, there is no exception.

My code of using mulithread looks like this:

ExecutorService executorService = Executors.newFixedThreadPool(numberOfPools);
ExecutorService securityExecutorService = new DelegatingSecurityContextExecutorService(executorService);

List<Callable<Result>> tasks = new ArrayList<>();
documentDataMap.forEach((key, value) -> tasks.add(() -> importData(key, value)));

List<Future<Result>> results = securityExecutorService.invokeAll(tasks);

In the function importData() I use “AddDocumentOperation addDocumentOperation” to create A12 document.

When I tried with numberOfPools=2, I still got that problem.

What should I do to solve this problem? Thank you!

Hi @nguyen-sharp-drift ,

this looks like a thread safety problem. The exception is from kernel and claims that the document created has more fields than defined in DM. This happens during serialization. It is very hard to know where is the problem from the code provided, but I have a couple of hints that might help:

  1. AddDocumentOperation operation is internal because it should not be called directly but rather through java/TS client. If you need to create documents in process, please use DocumentService. Operation uses internal events to synchronize with Solr. These synchronizations are based on thread local variables, which might overflow with code that you wrote.
  2. If you are really in a need of speed, and you run this code from job you should not care about extension points, security, validation, computations. You can use IDocumenRepository to save documents directly and later on update Solr.
  3. If this will also not suffice, I would recommend using prepared statements and save documents directly to the DOCUMENTS table. Please keep in mind that in version 2024.06 the documents are stored as JSON by default, while in 2023.06 XML is a default storage format.

This response is valid for DS version 37.2.0 - 36.0.0

Hi @tomas-thin-gale ,

Thanks for your answer and suggestion.
option 1: I can’t use it because of overflow
option 2: The importer is end users, so my project can’t apply that. (The imported excel file contains sensitive data, so it needs to be done by end users).
option 3: Same reason as option 2.

For now, using a single thread is fine for my project, but we need to increase the request timeout between the client and server. Otherwise, the connection will be terminated before the end user receives the import result if it takes too long.

Hi @nguyen-sharp-drift ,

Can you elaborate on option 1? I do not understand the justification about overflowing. The process is using thread local variables that are cleaned after the tread is put back into the pool. If you reuse threads, the thread local variables will use more and more of your memory until you free the thread. If you insist on using JSON-RPC, please create JSON-RPC request and send it to JSON-RPC server. This automatically cleans-up the thread local variables. This will make your processing slower because there will be JSON-RPC overhead, which you do not need.

If you write a job, you need to use DocumentService to import documents if security is to be applied or IDocumentRepository if you do not need security or any other higher level functions like (computation/validations). The problem with threads can be solved by injecting RollbackPostProcessor and calling {{clearCaches}} after each execution of a thread is done, and before it is assigned a new task. I do not recommend this approach because it RollbackPostProcessor is internal, but it might solve your problem right now.

I would recommend creating new operation that will add documents based on your input use proper transaction handling and DS public API and let the thread synchronization be done by DS automatically.

This response is valid for DS versions 37.2.0 - 36.0.0

Hi @nguyen-sharp-drift,
has your question been answered or do you need further support? If it is solved, please, use the checkbox to mark the solution to your problem so that other users also know what helped in your case.
Thanks in advance!
Denise from the Discourse team