diff --git a/api/db/services/document_counter_service.py b/api/db/services/document_counter_service.py index d079b5c54d..2e18375ff4 100644 --- a/api/db/services/document_counter_service.py +++ b/api/db/services/document_counter_service.py @@ -15,8 +15,7 @@ # import logging -from api.db.db_models import DB, Document -from api.db.services.document_service import DocumentService +from api.db.db_models import DB, Document, Knowledgebase def release_reparse_counters(doc_id): @@ -41,7 +40,35 @@ def release_reparse_counters(doc_id): if not (fresh.token_num or fresh.chunk_num or fresh.process_duration): logging.debug("release_reparse_counters: nothing to release for document %s", doc_id) return - DocumentService.increment_chunk_num(fresh.id, fresh.kb_id, -fresh.token_num, -fresh.chunk_num, -fresh.process_duration) + # Decrement directly inside the outer transaction. Do NOT call + # DocumentService.increment_chunk_num here: it is decorated with + # @DB.connection_context(), which closes the shared connection on exit. + # That would raise "Attempting to close database while transaction is + # open." because the outer DB.atomic() block is still open. + num = ( + Document.update( + token_num=Document.token_num - fresh.token_num, + chunk_num=Document.chunk_num - fresh.chunk_num, + process_duration=Document.process_duration - fresh.process_duration, + ) + .where((Document.id == fresh.id) & (Document.kb_id == fresh.kb_id)) + .execute() + ) + if num == 0: + raise LookupError("Document not found which is supposed to be there") + # Fetch and lock the knowledgebase row so existence is checked reliably. + # A bare UPDATE's num == 0 is ambiguous in MySQL (missing row vs. an + # unchanged update both report 0), so rely on the locked fetch instead. + kb = Knowledgebase.select().where(Knowledgebase.id == fresh.kb_id).for_update().first() + if kb is None: + raise LookupError("Knowledgebase not found which is supposed to be there") + # Only touch the knowledgebase aggregate when a token/chunk delta exists; + # otherwise the update would be a no-op that still reports num == 0. + if fresh.token_num or fresh.chunk_num: + Knowledgebase.update( + token_num=Knowledgebase.token_num - fresh.token_num, + chunk_num=Knowledgebase.chunk_num - fresh.chunk_num, + ).where(Knowledgebase.id == fresh.kb_id).execute() logging.debug( "release_reparse_counters: released document %s (token=%s chunk=%s duration=%s)", doc_id,