3737
3838# Circuit breaker configuration
3939MAX_CONSECUTIVE_FAILURES = 3
40+ SLOW_FILE_SYNC_WARNING_MS = 500
4041
4142
4243@dataclass
@@ -650,12 +651,14 @@ async def sync_file(
650651 logger .warning (f"Skipping file due to repeated failures: { path } " )
651652 return None , None
652653
654+ start_time = time .time ()
655+ is_markdown = self .file_service .is_markdown (path )
656+ file_kind = "markdown" if is_markdown else "regular"
657+
653658 try :
654- logger .debug (
655- f"Syncing file path={ path } is_new={ new } is_markdown={ self .file_service .is_markdown (path )} "
656- )
659+ logger .debug (f"Syncing file path={ path } is_new={ new } is_markdown={ is_markdown } " )
657660
658- if self . file_service . is_markdown ( path ) :
661+ if is_markdown :
659662 entity , checksum = await self .sync_markdown_file (path , new )
660663 else :
661664 entity , checksum = await self .sync_regular_file (path , new )
@@ -680,33 +683,63 @@ async def sync_file(
680683 logger .debug (
681684 f"File sync completed, path={ path } , entity_id={ entity .id } , checksum={ checksum [:8 ]} "
682685 )
686+ duration_ms = int ((time .time () - start_time ) * 1000 )
687+ if duration_ms >= SLOW_FILE_SYNC_WARNING_MS :
688+ logger .warning (
689+ f"Slow file sync detected: path={ path } , file_kind={ file_kind } , duration_ms={ duration_ms } "
690+ )
683691 return entity , checksum
684692
685693 except FileNotFoundError :
686694 # File exists in database but not on filesystem
687695 # This indicates a database/filesystem inconsistency - treat as deletion
688- logger .warning (
689- f"File not found during sync, treating as deletion: path={ path } . "
690- "This may indicate a race condition or manual file deletion."
691- )
692- await self .handle_delete (path )
696+ with telemetry .span (
697+ "sync.file.failure" ,
698+ failure_type = "file_not_found" ,
699+ path = path ,
700+ file_kind = file_kind ,
701+ is_new = new ,
702+ is_fatal = False ,
703+ ):
704+ logger .warning (
705+ f"File not found during sync, treating as deletion: path={ path } . "
706+ "This may indicate a race condition or manual file deletion."
707+ )
708+ await self .handle_delete (path )
693709 return None , None
694710
695711 except Exception as e :
712+ failure_type = type (e ).__name__
696713 # Check if this is a fatal error (or caused by one)
697714 # Fatal errors like project deletion should terminate sync immediately
698715 if isinstance (e , SyncFatalError ) or isinstance (
699716 e .__cause__ , SyncFatalError
700717 ): # pragma: no cover
701- logger .error (f"Fatal sync error encountered, terminating sync: path={ path } " )
718+ with telemetry .span (
719+ "sync.file.failure" ,
720+ failure_type = failure_type ,
721+ path = path ,
722+ file_kind = file_kind ,
723+ is_new = new ,
724+ is_fatal = True ,
725+ ):
726+ logger .error (f"Fatal sync error encountered, terminating sync: path={ path } " )
702727 raise
703728
704729 # Otherwise treat as recoverable file-level error
705730 error_msg = str (e )
706- logger .error (f"Failed to sync file: path={ path } , error={ error_msg } " )
731+ with telemetry .span (
732+ "sync.file.failure" ,
733+ failure_type = failure_type ,
734+ path = path ,
735+ file_kind = file_kind ,
736+ is_new = new ,
737+ is_fatal = False ,
738+ ):
739+ logger .error (f"Failed to sync file: path={ path } , error={ error_msg } " )
707740
708- # Record failure for circuit breaker
709- await self ._record_failure (path , error_msg )
741+ # Record failure for circuit breaker
742+ await self ._record_failure (path , error_msg )
710743
711744 return None , None
712745
@@ -1100,24 +1133,36 @@ async def resolve_relations(self, entity_id: int | None = None):
11001133 # update search index only on successful resolution
11011134 await self .search_service .index_entity (resolved_entity )
11021135 except IntegrityError :
1103- # IntegrityError means a relation with this (from_id, to_id, relation_type)
1104- # already exists. The UPDATE was rolled back, so our unresolved relation
1105- # (to_id=NULL) still exists in the database. We delete it because:
1106- # 1. It's redundant - a resolved relation already captures this relationship
1107- # 2. If we don't delete it, future syncs will try to resolve it again
1108- # and get the same IntegrityError
1109- logger .debug (
1110- "Deleting duplicate unresolved relation "
1111- f"relation_id={ relation .id } "
1112- f"from_id={ relation .from_id } "
1113- f"to_name={ relation .to_name } "
1114- f"resolved_to_id={ resolved_entity .id } "
1115- )
1116- try :
1117- await self .relation_repository .delete (relation .id )
1118- except Exception as e :
1119- # Log but don't fail - the relation may have been deleted already
1120- logger .debug (f"Could not delete duplicate relation { relation .id } : { e } " )
1136+ with telemetry .span (
1137+ "sync.relation.resolve_conflict" ,
1138+ relation_id = relation .id ,
1139+ relation_type = relation .relation_type ,
1140+ ):
1141+ # IntegrityError means a relation with this (from_id, to_id, relation_type)
1142+ # already exists. The UPDATE was rolled back, so our unresolved relation
1143+ # (to_id=NULL) still exists in the database. We delete it because:
1144+ # 1. It's redundant - a resolved version already captures this relationship
1145+ # 2. If we don't delete it, future syncs will try to resolve it again
1146+ # and get the same IntegrityError
1147+ logger .debug (
1148+ "Deleting duplicate unresolved relation "
1149+ f"relation_id={ relation .id } "
1150+ f"from_id={ relation .from_id } "
1151+ f"to_name={ relation .to_name } "
1152+ f"resolved_to_id={ resolved_entity .id } "
1153+ )
1154+ try :
1155+ await self .relation_repository .delete (relation .id )
1156+ except Exception as e :
1157+ with telemetry .span (
1158+ "sync.relation.cleanup_failure" ,
1159+ relation_id = relation .id ,
1160+ relation_type = relation .relation_type ,
1161+ ):
1162+ # Log but don't fail - the relation may have been deleted already
1163+ logger .debug (
1164+ f"Could not delete duplicate relation { relation .id } : { e } "
1165+ )
11211166
11221167 async def _quick_count_files (self , directory : Path ) -> int :
11231168 """Fast file count using find command.
0 commit comments