ifrit icon indicating copy to clipboard operation
ifrit copied to clipboard

Parallel grouper terminates unexpectedly

Open antonu17 opened this issue 6 years ago • 0 comments

Hi @tedsuo, First of all, I want to thank you for this library. I was looking for something like this and stumbled upon it. While testing if the library suits my use case, I think I've found a bug or at least an unexpected behavior. Let me share a sample of code that demonstrates it:

package main

import (
	"fmt"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"
	"log"
	"os"
	"syscall"
	"time"
)

func main() {
	log.Print("start")
	duration, _ := time.ParseDuration("10s")
	runner := &sleepRunner{duration: duration}
	group := grouper.NewParallel(nil, grouper.Members{
		{
			Name:   "sleeper",
			Runner: runner,
		},
	})

	rc := <-ifrit.Invoke(sigmon.New(group, syscall.SIGUSR1)).Wait()
	log.Print("finish: ", rc)
}

type sleepRunner struct {
	duration time.Duration
}

func (r *sleepRunner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	close(ready)
	wake := time.Tick(r.duration)
	log.Print("sleepRunner started")
	for {
		select {
		case sig := <-signals:
			log.Print("got signal: ", sig)
			if sig == os.Interrupt {
				return fmt.Errorf("interrupted")
			}
		case <-wake:
			log.Print("sleepRunner finished")
			return nil
		}
	}
}

If I run this code in a shell, and start sending USR1 signal to the process, the process ends:

$ go run main.go
2019/08/17 21:10:00 start
2019/08/17 21:10:00 sleepRunner started
2019/08/17 21:10:04 got signal: user defined signal 1
2019/08/17 21:10:05 got signal: user defined signal 1
2019/08/17 21:10:05 finish: <nil> # Notice, the process died after 5 seconds. If I don't send signals, it holds for 10 seconds, as required by duration.

# while this process is running I send signal USR1 from the separate shell like this:
$ pkill -USR1 main
$ pkill -USR1 main
...

No matter what signal I set to be propagated via sigmon (I tried USR1, USR2, URG), parallel grouper always dies on the second signal.

I'm pretty sure the bug is somewhere in grouper package, because if I run runner instead of group, like rc := <-ifrit.Invoke(sigmon.New(runner, syscall.SIGUSR1)).Wait(), it doesn't die after the second signal.

PS. Update: I'm using go version go1.12.7 darwin/amd64

antonu17 avatar Aug 17 '19 19:08 antonu17