• This repository has been archived on 04/Sep/2021
  • Stars
    star
    52
  • Rank 541,195 (Top 11 %)
  • Language
    Go
  • License
    Apache License 2.0
  • Created over 8 years ago
  • Updated over 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An exit strategy for go routines

An exit strategy for go routines.

Build Status Code Coverage Documentation

The library helps to end the go routines in your program and collects potential errors.

Install

go get github.com/simia-tech/go-exit

Example (main)

func main() {
	exit.Main.SetTimeout(2 * time.Second)

	counterExitSignal := exit.Main.NewSignal("counter")
	go func() {
		counter := 0

		var reply exit.Reply
		for reply == nil {
			select {
			case reply = <-counterExitSignal.Chan:
				break
			case <-time.After(1 * time.Second):
				counter++
				fmt.Printf("%d ", counter)
			}
		}

		switch {
		case counter%5 == 0:
			// Don't send a return via reply to simulate
			// an infinite running go routine. The timeout
			// should be hit in this case.
		case counter%2 == 1:
			reply.Err(fmt.Errorf("exit on the odd counter %d", counter))
		default:
			reply.Ok()
		}
	}()

	if report := exit.Main.ExitOn(syscall.SIGINT); report != nil {
		fmt.Println()
		report.WriteTo(os.Stderr)
		os.Exit(-1)
	}
	fmt.Println()
}

The default exit exit.Main should be used by the main program to exit it's go routines. If go-exit is used in a library, a separate exit should be created and used to end the library's go routines. This way the library stays independent from other exit code.

Example (library)

type Server struct {
	Address string
	exit    *exit.Exit
}

func New(address string) *Server {
	return &Server{
		Address: address,
		exit:    exit.New("server"),
	}
}

func (s *Server) Open() error {
	listener, err := net.Listen("tcp", s.Address)
	if err != nil {
		return err
	}

	signal := s.exit.NewSignal("acceptor")
	go func() {
		var reply exit.Reply

		go func() {
			for {
				connection, err := listener.Accept()
				if err != nil {
					if reply != nil && strings.Contains(
						err.Error(), "closed network connection") {
						reply.Ok()
					} else {
						reply.Err(err)
					}
					return
				}
				log.Printf("connected %v", connection.RemoteAddr())
				// handle connection
			}
		}()

		reply = <-signal.Chan
		if err := listener.Close(); err != nil {
			reply.Err(err)
		}
	}()

	return nil
}

func (s *Server) Close() error {
	if report := s.exit.Exit(); report != nil {
		return report
	}
	return nil
}

License

The project is licensed under Apache 2.0.