func Invoke(plan Plan) (err error) {

	defer func() {
		if err != nil {
			stopWorkers(plan.Init)
		}
	}()

	if err := plan.Validate(); err != nil {
		return errors.Trace(err)
	}
	catacomb := plan.Site
	if !atomic.CompareAndSwapInt32(&catacomb.dirty, 0, 1) {
		return errors.Errorf("catacomb %p has already been used", catacomb)
	}
	catacomb.adds = make(chan worker.Worker)

	// Add the Init workers right away, so the client can't induce data races
	// by modifying the slice post-return.
	for _, w := range plan.Init {
		catacomb.add(w)
	}

	// This goroutine listens for added workers until the catacomb is Killed.
	// We ensure the wg can't complete until we know no new workers will be
	// added.
	catacomb.wg.Add(1)
	go func() {
		defer catacomb.wg.Done()
		for {
			select {
			case <-catacomb.tomb.Dying():
				return
			case w := <-catacomb.adds:
				catacomb.add(w)
			}
		}
	}()

	// This goroutine runs the work func and stops the catacomb with its error;
	// and waits for for the listen goroutine and all added workers to complete
	// before marking the catacomb's tomb Dead.
	catacomb.tomb.Go(func() error {
		defer catacomb.wg.Wait()
		catacomb.Kill(runSafely(plan.Work))
		return nil
	})
	return nil
}
// Invoke uses the plan's catacomb to run the work func. It will return an
// error if the plan is not valid, or if the catacomb has already been used.
// If Invoke returns no error, the catacomb is now controlling the work func,
// and its exported methods can be called safely.
//
// Invoke takes responsibility for all workers in plan.Init, *whether or not
// it succeeds*.
Invoke uses the plan's catacomb to run the work func. It will return an
error if the plan is not valid, or if the catacomb has already been used.
If Invoke returns no error, the catacomb is now controlling the work func,
and its exported methods can be called safely.

Invoke takes responsibility for all workers in plan.Init, *whether or not
it succeeds*.
// Invoke uses the plan ' s catacomb to run the work func . It will return an // error if the plan is not valid or if the catacomb has already been used . // If Invoke returns no error the catacomb is now controlling the work func // and its exported methods can be called safely . // // Invoke takes responsibility for all workers in plan . Init * whether or not // it succeeds * .
func Invoke(plan Plan) (err error) {
	defer func() {
		if err != nil {
			stopWorkers(plan.Init)
		}
	}()
	if err := plan.Validate(); err != nil {
		return errors.Trace(err)
	}
	catacomb := plan.Site
	if !atomic.CompareAndSwapInt32(&catacomb.dirty, 0, 1) {
		return errors.Errorf("catacomb %p has already been used", catacomb)
	}
	catacomb.adds = make(chan worker.Worker)
	for _, w := range plan.Init {
		catacomb.add(w)
	}
	catacomb.wg.Add(1)
	go func() {
		defer catacomb.wg.Done()
		for {
			select {
			case <-catacomb.tomb.Dying():
				return
			case w := <-catacomb.adds:
				catacomb.add(w)
			}
		}
	}()
	catacomb.tomb.Go(func() error {
		defer catacomb.wg.Wait()
		catacomb.Kill(runSafely(plan.Work))
		return nil
	})
	return nil
}
func Invoke ( plan Plan ) ( err error ) { defer func ( ) { if err != nil { stopWorkers ( plan . Init ) } } ( ) if err := plan . Validate ( ) ; err != nil { return errors . Trace ( err ) } catacomb := plan . Site if ! atomic . CompareAndSwapInt32 ( & catacomb . dirty , 0 , 1 ) { return errors . Errorf ( " " , catacomb ) } catacomb . adds = make ( chan worker . Worker ) for _ , w := range plan . Init { catacomb . add ( w ) } catacomb . wg . Add ( 1 ) go func ( ) { defer catacomb . wg . Done ( ) for { select { case <- catacomb . tomb . Dying ( ) : return case w := <- catacomb . adds : catacomb . add ( w ) } } } ( ) catacomb . tomb . Go ( func ( ) error { defer catacomb . wg . Wait ( ) catacomb . Kill ( runSafely ( plan . Work ) ) return nil } ) return nil }
Invoke uses the plan's catacomb to run the work func.
Invoke uses the plan ' s catacomb to run the work func .
// Add the Init workers right away, so the client can't induce data races // by modifying the slice post-return. // This goroutine listens for added workers until the catacomb is Killed. // We ensure the wg can't complete until we know no new workers will be // added. // This goroutine runs the work func and stops the catacomb with its error; // and waits for for the listen goroutine and all added workers to complete // before marking the catacomb's tomb Dead.