Skip to content

Instantly share code, notes, and snippets.

@fentas
Created May 26, 2020 07:10
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save fentas/04c1e59f6cde0defaa16d8f8ecc78f89 to your computer and use it in GitHub Desktop.
Save fentas/04c1e59f6cde0defaa16d8f8ecc78f89 to your computer and use it in GitHub Desktop.
♻ Endless running goroutine. Restart process if it fails. Manage multiple processes.
package main
import (
"log"
// replace right path
"[...]/utils"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var logger *zap.Logger
func init() {
var err error
config := zap.NewDevelopmentConfig()
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
logger, err = config.Build()
if err != nil {
log.Fatalf("can't initialize zap logger: %v", err)
}
// logger, _ := zap.NewProduction()
defer logger.Sync()
}
func main() {
// setup processes
procs := utils.Processes{}
procs.Add(logger, "webserver", http.Webserver)
procs.Add(logger, "sshd", sshd.Socket)
procs.Add(logger, "other", odther.Socket)
// endless running process
logger.Info("Starting all go rotines")
procs.Run(logger)
}
package utils
import (
"fmt"
"time"
"go.uber.org/zap"
)
type run func(*zap.Logger) error
type process struct {
id string
err error
logger *zap.Logger
run run
}
// Start the process
func (proc *process) Start(channel chan<- *process) (err error) {
// make my goroutine signal its death, wether it's a panic or a return
defer func() {
if r := recover(); r != nil {
if err, ok := r.(error); ok {
proc.err = err
} else {
proc.err = fmt.Errorf("Panic happened with %v", r)
}
} else {
proc.err = err
}
channel <- proc
}()
return proc.run(proc.logger)
}
// Processes collects sub processes
type Processes struct {
list []*process
}
// Add a process
func (procs *Processes) Add(logger *zap.Logger, id string, fn run) {
procs.list = append(procs.list, &process{
id: id,
logger: logger.With(zap.String("process", id)),
run: fn,
})
}
// Run all processes
func (procs *Processes) Run(logger *zap.Logger) {
// process count
processes := len(procs.list)
// make a buffered channel with the space for my 10 workers
channel := make(chan *process, processes)
// go through all registered processes
for _, proc := range procs.list {
// start processes
go proc.Start(channel)
}
// read the channel, it will block until something is written,
// then it will restart the process
for proc := range channel {
// log the error
logger.Warn("Process stopped with err",
zap.String("process", proc.id),
zap.Error(proc.err),
)
// reset err
proc.err = nil
// give it a little time
time.Sleep(1 * time.Second)
// a goroutine has ended, restart it
go proc.Start(channel)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment