func (m *Main) Kill(reason error) {
	m.l.Lock()
	defer m.l.Unlock()
	log(nil, reason).Info("shutting down")
	shutdownStart := time.Now()
	deadline := time.After(m.shutdownDeadline)
	ctx := context.Background()
	alive := m.components
	inverseDeps := inverseDependencies(m.components)
	for len(alive) > 0 {
		var killed []Component
		for _, component := range alive {
			if isReadyToKill(inverseDeps, component) {
				component.Tomb().Kill(reason)
				killed = append(killed, component)
			}
		}
		if !waitAny(killed, deadline) {
			for _, component := range alive {
				metrics.GenMainShutdown.Duration(ctx, time.Since(shutdownStart), statsd.Tags{
					"success":       false,
					"deadline":      m.shutdownDeadline,
					"mainComponent": componentName(component),
				})
				log(ctx, component.Tomb().Err()).
					WithField("mainComponent", componentName(component)).
					Error("component took too long to shut down")
			}
			return
		}
		i := 0
		for _, component := range alive {
			if isDead(component.Tomb()) {
				metrics.GenMainShutdown.Duration(ctx, time.Since(shutdownStart), statsd.Tags{
					"success":       true,
					"deadline":      m.shutdownDeadline,
					"mainComponent": componentName(component),
				})
				log(ctx, component.Tomb().Err()).
					WithField("mainComponent", componentName(component)).
					Debug("component shutdown notification")
			} else {
				alive[i] = component
				i++
			}
		}
		alive = alive[0:i]
	}
}
Kill will terminate all running components with a given reason
package genmain
import (
	"context"
	"errors"
	"fmt"
	"os"
	"os/signal"
	"reflect"
	"strings"
	"sync"
	"syscall"
	"time"
	"gopkg.in/tomb.v2"
	"github.com/Shopify/goose/logger"
	"github.com/Shopify/goose/metrics"
	"github.com/Shopify/goose/safely"
	"github.com/Shopify/goose/statsd"
)
var log = logger.New("genmain")
const defaultShutdownDeadline = 3 * time.Second
var (
	ErrCanOnlyRunOnce = errors.New("can only run once")
	ErrShutdownRequested = errors.New("shutdown requested")
)
type Main struct {
	components       []Component
	shutdownDeadline time.Duration
	l   sync.Mutex
	ran bool
}
func New(components ...Component) Main {
	return Main{
		components:       components,
		shutdownDeadline: defaultShutdownDeadline,
	}
}
type SignalError struct {
	signal os.Signal
}
func (s *SignalError) Error() string {
	return fmt.Sprintf("received signal: %v", s.signal)
}
func waitAny(components []Component, deadline <-chan time.Time) bool {
	cases := make([]reflect.SelectCase, len(components)+1)
	for i, component := range components {
		cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(component.Tomb().Dead())}
	}
	cases[len(components)] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(deadline)}
	chosen, _, _ := reflect.Select(cases)
	return chosen < len(components)
}
func dependencies(component Component) []Component {
	if c, ok := component.(ComponentWithDependencies); ok {
		return c.Dependencies()
	}
	return nil
}
func inverseDependencies(components []Component) map[Component][]Component {
	inverse := make(map[Component][]Component, len(components))
	for _, component := range components {
		for _, dep := range dependencies(component) {
			inverse[dep] = append(inverse[dep], component)
		}
	}
	return inverse
}
func isReadyToKill(inverse map[Component][]Component, component Component) bool {
	if deps, ok := inverse[component]; ok {
		for _, dep := range deps {
			if !isDead(dep.Tomb()) {
				return false
			}
		}
	}
	return true
}
func isDead(t *tomb.Tomb) bool {
	select {
	case <-t.Dead():
		return true
	default:
		return false
	}
}