func (s *executionServer) runShuffle(sctx sif.StageContext, req *pb.MRunStageRequest) (err error) {
	buckets := make([]uint64, 0)
	targets := make([]pb.PartitionsServiceClient, 0)
	for i := 0; i < len(req.Buckets); i++ {
		if req.Buckets[i] != req.AssignedBucket {
			conn, err := dialWorker(req.Workers[i])
			partitionClient := pb.NewPartitionsServiceClient(conn)
			if err != nil {
				return err
			}
			targets = append(targets, partitionClient)
			buckets = append(buckets, req.Buckets[i])
			defer conn.Close()
		}
	}
	s.planExecutor.AssignShuffleBucket(req.AssignedBucket)
	var fetchWg, mergeWg sync.WaitGroup
	asyncFetchErrors := make(chan error, len(buckets))  
	asyncMergeErrors := make(chan error, 1)             
	partChan := make(chan sif.ReduceablePartition, len(buckets))
	defer close(asyncMergeErrors)
	defer func() {
		select {
		case mergeErr := <-asyncMergeErrors:
			if s.onRowError(sctx, mergeErr) != nil {
				err = mergeErr
			}
		default:
		}
	}()
	defer close(asyncFetchErrors)  
	defer func() {
		select {
		case fetchErr := <-asyncFetchErrors:
			if s.onRowError(sctx, fetchErr) != nil {
				err = fetchErr
			}
		default:
		}
	}()
	defer mergeWg.Wait()   
	defer close(partChan)  
	defer fetchWg.Wait()   
	mergeWg.Add(1)
	go s.planExecutor.MergeShuffledPartitions(sctx, &mergeWg, partChan, asyncMergeErrors)
	t := 0
	concurrentFetchLimit := 4
	activeFetches := 0
	for {
		if len(targets) == 0 {
			break
		}
		shuffleReq := &pb.MShufflePartitionRequest{Bucket: req.AssignedBucket}
		res, err := targets[t].ShufflePartition(sctx, shuffleReq)
		if err != nil {
			return err
		} else if !res.Ready {
			continue  
		} else if res.Part != nil {
			transferReq := &pb.MTransferPartitionDataRequest{Id: res.Part.Id}
			stream, err := targets[t].TransferPartitionData(sctx, transferReq)
			if err != nil {
				return err
			}
			fetchWg.Add(1)
			activeFetches++
			go s.planExecutor.ShufflePartitionData(&fetchWg, partChan, asyncFetchErrors, res.Part, stream)
		}
		if !res.HasNext {
			copy(buckets[t:], buckets[t+1:])
			buckets = buckets[:len(buckets)-1]
			copy(targets[t:], targets[t+1:])
			targets[len(targets)-1] = nil  
			targets = targets[:len(targets)-1]
		}
		if activeFetches >= concurrentFetchLimit {
			fetchWg.Wait()
			activeFetches = 0
			select {
			case fetchErr := <-asyncFetchErrors:
				if err := s.onRowError(sctx, fetchErr); err != nil {
					return err
				}
			default:
			}
			select {
			case mergeErr := <-asyncMergeErrors:
				if mergeErr != nil {
					return mergeErr
				}
			default:
			}
		}
		if len(targets) > 0 {
			t = (t + 1) % len(targets)
		}
	}
	return nil
}
runShuffle executes a prepared shuffle on a Worker
package cluster
import (
	"context"
	"fmt"
	"log"
	"sync"
	"github.com/go-sif/sif"
	pb "github.com/go-sif/sif/internal/rpc"
	"github.com/go-sif/sif/internal/stats"
	itypes "github.com/go-sif/sif/internal/types"
	iutil "github.com/go-sif/sif/internal/util"
	logging "github.com/go-sif/sif/logging"
	"github.com/hashicorp/go-multierror"
)
type executionServer struct {
	planExecutor itypes.PlanExecutor
	logClient    pb.LogServiceClient
	statsTracker *stats.RunStatistics
}
func createExecutionServer(logClient pb.LogServiceClient, planExecutor itypes.PlanExecutor, statsTracker *stats.RunStatistics) *executionServer {
	return &executionServer{logClient: logClient, planExecutor: planExecutor, statsTracker: statsTracker}
}
func (s *executionServer) RunStage(ctx context.Context, req *pb.MRunStageRequest) (*pb.MRunStageResponse, error) {
	if !s.planExecutor.HasNextStage() {
		return nil, fmt.Errorf("plan Executor %s does not have a next stage to run (stage %d expected)", s.planExecutor.ID(), req.StageId)
	}
	onRowErrorWithContext := func(err error) error {
		return s.onRowError(ctx, err)
	}
	stage := s.planExecutor.GetNextStage()
	if stage.ID() != int(req.StageId) {
		return nil, fmt.Errorf("next stage on worker (%d) does not match expected (%d)", stage.ID(), req.StageId)
	}
	sctx := createStageContext(ctx, stage)
	if req.Buckets != nil {
		sctx.SetShuffleBuckets(req.Buckets)
	}
	err := s.planExecutor.InitStageContext(sctx, stage)
	if err != nil {
		return nil, err
	}
	log.Println("------------------------------")
	log.Printf("Running stage %d...", req.StageId)
	defer func() {
		log.Printf("Finished running stage %d", req.StageId)
		log.Println("------------------------------")
	}()
	s.statsTracker.StartStage()
	s.statsTracker.StartTransform()
	log.Printf("Mapping partitions in stage %d...", req.StageId)
	err = s.planExecutor.TransformPartitions(sctx, stage.WorkerExecute, onRowErrorWithContext)
	if err != nil {
		if _, ok := err.(*multierror.Error); !s.planExecutor.GetConf().IgnoreRowErrors || !ok {
			s.statsTracker.EndTransform(stage.ID())
			log.Printf("Failed to map in stage %d: %e", req.StageId, err)
			return nil, err
		}
	}
	log.Printf("Finished mapping partitions in stage %d", req.StageId)
	s.statsTracker.EndTransform(stage.ID())
	if req.RunShuffle {
		log.Printf("Shuffling partitions in stage %d...", req.StageId)
		s.statsTracker.StartShuffle()
		err = s.runShuffle(sctx, req)
		if err != nil {
			s.statsTracker.EndShuffle(stage.ID())
			log.Printf("Failed to shuffle in stage %d: %e", req.StageId, err)
			return nil, err
		}
		log.Printf("Finished shuffling partitions in stage %d", req.StageId)
		s.statsTracker.EndShuffle(stage.ID())
	}
	s.statsTracker.EndStage(stage.ID())
	return &pb.MRunStageResponse{}, nil
}
func (s *executionServer) onRowError(ctx context.Context, err error) (outgoingErr error) {
	defer func() {
		if r := recover(); r != nil {
			if anErr, ok := r.(error); ok {
				outgoingErr = anErr
			} else {
				outgoingErr = fmt.Errorf("panic was not an error")
			}
		}
	}()
	if multierr, ok := err.(*multierror.Error); s.planExecutor.GetConf().IgnoreRowErrors && ok {
		multierr.ErrorFormat = iutil.FormatMultiError
		logger, err := s.logClient.Log(ctx)
		if err != nil {
			return err
		}
		err = logger.Send(&pb.MLogMsg{
			Level:   logging.ErrorLevel,
			Source:  s.planExecutor.ID(),
			Message: fmt.Sprintf("Map error in stage %d:\n%s", s.planExecutor.GetCurrentStage().ID(), multierr.Error()),
		})
		if err != nil {
			return err
		}
		_, err = logger.CloseAndRecv()
		if err != nil {
			return err
		}
	} else {
		return err
	}
	return nil
}