internal/praefect/backup_repository.go (56 lines of code) (raw):

package praefect import ( "errors" "fmt" "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage" "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore" "gitlab.com/gitlab-org/gitaly/v16/internal/structerr" "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb" "google.golang.org/grpc" "google.golang.org/protobuf/proto" ) // BackupRepositoryHandler handles routing of the BackupRepository RPC. func BackupRepositoryHandler(router Router) grpc.StreamHandler { return func(srv any, stream grpc.ServerStream) error { var req gitalypb.BackupRepositoryRequest if err := stream.RecvMsg(&req); err != nil { return fmt.Errorf("receive request: %w", err) } repo := req.GetRepository() if repo == nil { return structerr.NewInvalidArgument("%w", storage.ErrRepositoryNotSet) } ctx := stream.Context() virtualStorage := repo.GetStorageName() var conn *grpc.ClientConn var targetStorage string var replicaPath string // Try normal routing first (for existing repositories) repositoryRoute, err := router.RouteRepositoryAccessor(ctx, virtualStorage, repo.GetRelativePath(), false) if err == nil { targetStorage = repositoryRoute.Node.Storage conn = repositoryRoute.Node.Connection replicaPath = repositoryRoute.ReplicaPath } else { // If repository doesn't exist, pick any healthy node if errors.Is(err, datastore.ErrRepositoryNotFound) { storageRoute, err := router.RouteStorageAccessor(ctx, virtualStorage) if err != nil { return err } targetStorage = storageRoute.Storage conn = storageRoute.Connection } else { return err } } rewritten := proto.Clone(&req).(*gitalypb.BackupRepositoryRequest) rewritten.Repository.StorageName = targetStorage if replicaPath != "" { rewritten.Repository.RelativePath = replicaPath } client := gitalypb.NewRepositoryServiceClient(conn) resp, err := client.BackupRepository(ctx, rewritten) if err != nil { return err } return stream.SendMsg(resp) } }