runner icon indicating copy to clipboard operation
runner copied to clipboard

thoughts on supporting functions that return errors and handling pancis

Open dvic opened this issue 7 years ago • 1 comments

What are your thoughts on adding support for getting errors back and thereby also handling panics, e.g.,

// RunErr runs a function of type func() error in a new goroutine.
// The returned channel is closed when f returns.
func (r *Runner) RunErr(f func() error) <-chan error {
	done := make(chan error, 1)
	r.wg.Add(1)
	go func() {
		var ret error
		defer func() {
			rec := recover()
			if recErr, ok := rec.(error); ok {
				ret = recErr
			} else if rec != nil {
				ret = errors.New(fmt.Sprintf("panic: %+v", rec))
			}
			done <- ret
			close(done)
			r.wg.Done()
		}()
		ret = f()
	}()
	return done
}

(and also RunErrContext and RunErrOtherContext)

dvic avatar Mar 01 '18 21:03 dvic

And a bit related, what about a Done() <-chan struct{}:

func (r *Runner) Done() <-chan struct{} {
	done := make(chan struct{})
	go func() {
		r.Wait()
		close(done)
	}()
	return done
}

The reason I'm asking is because then you can do things like:

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	r := runner.Runner{Ctx: ctx}

	httpTask := r.RunErrContext(runHTTP)
	tcpTask := r.RunErrContext(runTCP)
	signalTask := r.RunSigs(syscall.SIGINT, syscall.SIGTERM)

Loop:
	for {
		select {
		case <-signalTask:
			// setting channel to nil so it won't fire again next round
			signalTask = nil 
			cancel()
		case err := <-httpTask:
			// if http errors, stop everything
			httpTask = nil
			if err != nil {
				cancel()
			}
		case <-tcpTask:
			// don't care about tcp error
			tcpTask = nil
		case <-r.Done():
			// when wg is done, all goroutines have finished
			fmt.Println("All done")
			break Loop
		}
	}
}

(assuming wg.Done() is called in goroutine after close(done)

dvic avatar Mar 01 '18 22:03 dvic