func (r Restarter) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	if r.Load == nil {
		return ErrNoLoadCallback
	}

	process := ifrit.Background(r.Runner)
	processReady := process.Ready()
	exit := process.Wait()
	signaled := false

	for {
		select {
		case signal := <-signals:
			process.Signal(signal)
			signaled = true

		case <-processReady:
			close(ready)
			processReady = nil

		case err := <-exit:
			if signaled {
				return err
			}

			r.Runner = r.Load(r.Runner, err)
			if r.Runner == nil {
				return err
			}
			process = ifrit.Background(r.Runner)
			exit = process.Wait()
		}
	}
}
Example #2
0
func New(proxySignals <-chan os.Signal, runner ifrit.Runner) ifrit.Runner {
	return ifrit.RunFunc(func(signals <-chan os.Signal, ready chan<- struct{}) error {
		process := ifrit.Background(runner)
		<-process.Ready()
		close(ready)
		go forwardSignals(proxySignals, process)
		go forwardSignals(signals, process)
		return <-process.Wait()
	})
}
func Invoke(runner ifrit.Runner) ifrit.Process {
	process := ifrit.Background(runner)

	select {
	case <-process.Ready():
	case err := <-process.Wait():
		ginkgo.Fail(fmt.Sprintf("process failed to start: %s", err))
	}

	return process
}
func (g *orderedGroup) orderedStart(signals <-chan os.Signal) (os.Signal, ErrorTrace) {
	for _, member := range g.members {
		p := ifrit.Background(member)
		select {
		case <-p.Ready():
			g.pool[member.Name] = p
		case err := <-p.Wait():
			return nil, ErrorTrace{
				ExitEvent{Member: member, Err: err},
			}
		case signal := <-signals:
			return signal, nil
		}
	}

	return nil, nil
}
func (g *parallelGroup) parallelStart(signals <-chan os.Signal) (os.Signal, ErrorTrace) {
	numMembers := len(g.members)

	cases := make([]reflect.SelectCase, 2*numMembers+1)

	for i, member := range g.members {
		process := ifrit.Background(member)

		g.pool[member.Name] = process

		cases[2*i] = reflect.SelectCase{
			Dir:  reflect.SelectRecv,
			Chan: reflect.ValueOf(process.Wait()),
		}

		cases[2*i+1] = reflect.SelectCase{
			Dir:  reflect.SelectRecv,
			Chan: reflect.ValueOf(process.Ready()),
		}
	}

	cases[2*numMembers] = reflect.SelectCase{
		Dir:  reflect.SelectRecv,
		Chan: reflect.ValueOf(signals),
	}

	numReady := 0
	for {
		chosen, recv, _ := reflect.Select(cases)

		switch {
		case chosen == 2*numMembers:
			return recv.Interface().(os.Signal), nil
		case chosen%2 == 0:
			recvError, _ := recv.Interface().(error)
			return nil, ErrorTrace{ExitEvent{Member: g.members[chosen/2], Err: recvError}}
		default:
			cases[chosen].Chan = reflect.Zero(cases[chosen].Chan.Type())
			numReady++
			if numReady == numMembers {
				return nil, nil
			}
		}
	}
}
	var (
		lifecycle        ifrit.Process
		fakeDeamonRunner func(signals <-chan os.Signal, ready chan<- struct{}) error
	)

	BeforeEach(func() {
		builder := main.Builder{
			RepoName:            "ubuntu",
			Tag:                 "latest",
			OutputFilename:      "/tmp/result/result.json",
			DockerDaemonTimeout: 300 * time.Millisecond,
			CacheDockerImage:    true,
		}

		lifecycle = ifrit.Background(grouper.NewParallel(os.Interrupt, grouper.Members{
			{"builder", ifrit.RunFunc(builder.Run)},
			{"fake_docker_daemon", ifrit.RunFunc(fakeDeamonRunner)},
		}))
	})

	AfterEach(func() {
		ginkgomon.Interrupt(lifecycle)
	})

	Context("when the daemon won't start", func() {
		fakeDeamonRunner = func(signals <-chan os.Signal, ready chan<- struct{}) error {
			close(ready)
			select {
			case signal := <-signals:
				return errors.New(signal.String())
			case <-time.After(1 * time.Second):
				// Daemon "crashes" after a while
	var testRunner *fake_runner.TestRunner
	var restarter restart.Restarter
	var process ifrit.Process

	BeforeEach(func() {
		testRunner = fake_runner.NewTestRunner()
		restarter = restart.Restarter{
			Runner: testRunner,
			Load: func(runner ifrit.Runner, err error) ifrit.Runner {
				return nil
			},
		}
	})

	JustBeforeEach(func() {
		process = ifrit.Background(restarter)
	})

	AfterEach(func() {
		process.Signal(os.Kill)
		testRunner.EnsureExit()
		Eventually(process.Wait()).Should(Receive())
	})

	Describe("Process Behavior", func() {

		It("waits for the internal runner to be ready", func() {
			Consistently(process.Ready()).ShouldNot(BeClosed())
			testRunner.TriggerReady()
			Eventually(process.Ready()).Should(BeClosed())
		})
		}

		groupRunner = grouper.NewParallel(os.Interrupt, members)
	})

	AfterEach(func() {
		childRunner1.EnsureExit()
		childRunner2.EnsureExit()
		childRunner3.EnsureExit()

		ginkgomon.Kill(groupProcess)
	})

	Describe("Start", func() {
		BeforeEach(func() {
			groupProcess = ifrit.Background(groupRunner)
		})

		It("runs all runners at the same time", func() {
			Eventually(childRunner1.RunCallCount).Should(Equal(1))
			Eventually(childRunner2.RunCallCount).Should(Equal(1))
			Eventually(childRunner3.RunCallCount).Should(Equal(1))

			Consistently(groupProcess.Ready()).ShouldNot(BeClosed())

			childRunner1.TriggerReady()
			childRunner2.TriggerReady()
			childRunner3.TriggerReady()

			Eventually(groupProcess.Ready()).Should(BeClosed())
		})
	"github.com/cloudfoundry-incubator/docker_app_lifecycle/Godeps/_workspace/src/github.com/tedsuo/ifrit/proxy"

	. "github.com/cloudfoundry-incubator/docker_app_lifecycle/Godeps/_workspace/src/github.com/onsi/ginkgo"
	. "github.com/cloudfoundry-incubator/docker_app_lifecycle/Godeps/_workspace/src/github.com/onsi/gomega"
)

var _ = Describe("Proxy", func() {
	var testRunner *fake_runner.TestRunner
	var process ifrit.Process
	var proxySignals chan os.Signal
	var receivedSignals <-chan os.Signal

	BeforeEach(func() {
		proxySignals = make(chan os.Signal, 1)
		testRunner = fake_runner.NewTestRunner()
		process = ifrit.Background(proxy.New(proxySignals, testRunner))
		receivedSignals = testRunner.WaitForCall()
		testRunner.TriggerReady()
	})

	It("sends the proxied signals to the embedded runner", func() {
		proxySignals <- os.Interrupt
		Eventually(receivedSignals).Should(Receive(Equal(os.Interrupt)))
	})

	It("sends the process signals to the embedded runner", func() {
		process.Signal(os.Interrupt)
		Eventually(receivedSignals).Should(Receive(Equal(os.Interrupt)))
	})
})