@@ -820,3 +820,75 @@ func (s *Coordinator) CleanupExpiredPartialAttachedFunctions(ctx context.Context
820820 CleanedUpIds : cleanedAttachedFunctionIDStrings ,
821821 }, nil
822822}
823+
824+ // GetSoftDeletedAttachedFunctions retrieves attached functions that are soft deleted and were updated before the cutoff time
825+ func (s * Coordinator ) GetSoftDeletedAttachedFunctions (ctx context.Context , req * coordinatorpb.GetSoftDeletedAttachedFunctionsRequest ) (* coordinatorpb.GetSoftDeletedAttachedFunctionsResponse , error ) {
826+ log := log .With (zap .String ("method" , "GetSoftDeletedAttachedFunctions" ))
827+
828+ if req .CutoffTime == nil {
829+ log .Error ("GetSoftDeletedAttachedFunctions: cutoff_time is required" )
830+ return nil , status .Errorf (codes .InvalidArgument , "cutoff_time is required" )
831+ }
832+
833+ if req .Limit <= 0 {
834+ log .Error ("GetSoftDeletedAttachedFunctions: limit must be greater than 0" )
835+ return nil , status .Errorf (codes .InvalidArgument , "limit must be greater than 0" )
836+ }
837+
838+ cutoffTime := req .CutoffTime .AsTime ()
839+ attachedFunctions , err := s .catalog .metaDomain .AttachedFunctionDb (ctx ).GetSoftDeletedAttachedFunctions (cutoffTime , req .Limit )
840+ if err != nil {
841+ log .Error ("GetSoftDeletedAttachedFunctions: failed to get soft deleted attached functions" , zap .Error (err ))
842+ return nil , err
843+ }
844+
845+ // Convert to proto response
846+ protoAttachedFunctions := make ([]* coordinatorpb.AttachedFunction , len (attachedFunctions ))
847+ for i , af := range attachedFunctions {
848+ protoAttachedFunctions [i ] = & coordinatorpb.AttachedFunction {
849+ Id : af .ID .String (),
850+ Name : af .Name ,
851+ InputCollectionId : af .InputCollectionID ,
852+ OutputCollectionName : af .OutputCollectionName ,
853+ CompletionOffset : uint64 (af .CompletionOffset ),
854+ MinRecordsForInvocation : uint64 (af .MinRecordsForInvocation ),
855+ CreatedAt : uint64 (af .CreatedAt .Unix ()),
856+ UpdatedAt : uint64 (af .UpdatedAt .Unix ()),
857+ }
858+
859+ protoAttachedFunctions [i ].NextRunAt = uint64 (af .NextRun .Unix ())
860+ if af .OutputCollectionID != nil {
861+ protoAttachedFunctions [i ].OutputCollectionId = proto .String (* af .OutputCollectionID )
862+ }
863+ }
864+
865+ log .Info ("GetSoftDeletedAttachedFunctions: completed successfully" ,
866+ zap .Int ("count" , len (attachedFunctions )))
867+
868+ return & coordinatorpb.GetSoftDeletedAttachedFunctionsResponse {
869+ AttachedFunctions : protoAttachedFunctions ,
870+ }, nil
871+ }
872+
873+ // FinishAttachedFunctionDeletion permanently deletes an attached function from the database (hard delete)
874+ // This should only be called after the soft delete grace period has passed
875+ func (s * Coordinator ) FinishAttachedFunctionDeletion (ctx context.Context , req * coordinatorpb.FinishAttachedFunctionDeletionRequest ) (* coordinatorpb.FinishAttachedFunctionDeletionResponse , error ) {
876+ log := log .With (zap .String ("method" , "FinishAttachedFunctionDeletion" ))
877+
878+ attachedFunctionID , err := uuid .Parse (req .Id )
879+ if err != nil {
880+ log .Error ("FinishAttachedFunctionDeletion: invalid attached_function_id" , zap .Error (err ))
881+ return nil , status .Errorf (codes .InvalidArgument , "invalid attached_function_id: %v" , err )
882+ }
883+
884+ err = s .catalog .metaDomain .AttachedFunctionDb (ctx ).HardDeleteAttachedFunction (attachedFunctionID )
885+ if err != nil {
886+ log .Error ("FinishAttachedFunctionDeletion: failed to hard delete attached function" , zap .Error (err ))
887+ return nil , err
888+ }
889+
890+ log .Info ("FinishAttachedFunctionDeletion: completed successfully" ,
891+ zap .String ("attached_function_id" , attachedFunctionID .String ()))
892+
893+ return & coordinatorpb.FinishAttachedFunctionDeletionResponse {}, nil
894+ }
0 commit comments