{ var wg sync.WaitGroup pCtx, ctxCancelFn := context.WithCancel(ctx) stageCh := make([]chan Payload, len(p.stages)+1) errCh := make(chan error, len(p.stages)+2) for i := 0; i < len(stageCh); i++ { stageCh[i] = make(chan Payload) } for i := 0; i < len(p.stages); i++ { wg.Add(1) go func(stageIndex int) { p.stages[stageIndex].Run(pCtx, &workerParams{ stage: stageIndex, inCh: stageCh[stageIndex], outCh: stageCh[stageIndex+1], errCh: errCh, }) close(stageCh[stageIndex+1]) wg.Done() }(i) } wg.Add(2) go func() { sourceWorker(pCtx, source, stageCh[0], errCh) close(stageCh[0]) wg.Done() }() go func() { sinkWorker(pCtx, sink, stageCh[len(stageCh)-1], errCh) wg.Done() }() go func() { wg.Wait() close(errCh) ctxCancelFn() }() var err error for pErr := range errCh { err = multierror.Append(err, pErr) ctxCancelFn() } return err }