Last active
October 15, 2023 20:59
-
-
Save geberl/3f614bad90be1b00bad369325d3642a9 to your computer and use it in GitHub Desktop.
Example oklog/run group
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"net/http" | |
"os" | |
"syscall" | |
"github.com/go-kit/kit/log" | |
"github.com/go-kit/kit/log/level" | |
"github.com/gorilla/mux" | |
"github.com/oklog/run" | |
) | |
func main() { | |
logger := MakeLogger("debug") | |
level.Debug(logger).Log("msg", "hello") | |
var ( | |
g run.Group | |
ctx = context.Background() | |
) | |
ctx, cancel := context.WithCancel(ctx) | |
/* | |
Add an actor (function) to the group. | |
Each actor must be pre-emptable by an interrupt function. | |
That is, if interrupt is invoked, execute should return. | |
Also, it must be safe to call interrupt even after execute has returned. | |
The first actor (function) to return interrupts all running actors. | |
The error is passed to the interrupt functions, and is returned by Run. | |
*/ | |
// Other func 1 | |
{ | |
g.Add(func() error { | |
level.Debug(logger).Log("msg", "other func 1 g add") | |
for { | |
if ctx.Err() != nil { | |
// level.Debug(logger).Log("msg", "other func 1 context cancel") | |
break | |
} | |
} | |
return nil | |
}, func(err error) { | |
level.Debug(logger).Log("msg", "other func 1 g interrupt func") | |
cancel() | |
}) | |
} | |
// Other func 2 | |
{ | |
g.Add(func() error { | |
level.Debug(logger).Log("msg", "other func 2 g add") | |
for { | |
if ctx.Err() != nil { | |
// level.Debug(logger).Log("msg", "other func 2 context cancel") | |
break | |
} | |
} | |
return nil | |
}, func(err error) { | |
level.Debug(logger).Log("msg", "other func 2 g interrupt") | |
cancel() | |
}) | |
} | |
// gorilla/mux based API | |
{ | |
router := &mux.Router{} | |
server := &http.Server{Addr: ":8080", Handler: router} | |
g.Add(func() error { | |
level.Debug(logger).Log("msg", "api func g add func") | |
return server.ListenAndServe() | |
}, func(err error) { | |
level.Debug(logger).Log("msg", "api func g interrupt func") | |
if err := server.Shutdown(ctx); err != nil { | |
level.Error(logger).Log("msg", "failed to gracefully exit api", "err", err) | |
} | |
}) | |
} | |
// Signal handler | |
{ | |
execute, interrupt := run.SignalHandler(ctx, syscall.SIGTERM, syscall.SIGINT) | |
g.Add(func() error { | |
level.Debug(logger).Log("msg", "signal func g add") | |
err := execute() | |
if se, ok := err.(run.SignalError); ok { | |
level.Info(logger).Log("signal", se.Signal) | |
return nil | |
} | |
return err | |
}, func(err error) { | |
level.Debug(logger).Log("msg", "signal func g interrupt") | |
interrupt(err) | |
}) | |
} | |
if err := g.Run(); err != nil { | |
level.Error(logger).Log("msg", "error running groups", "err", err) | |
os.Exit(1) | |
} | |
level.Debug(logger).Log("msg", "clean exit") | |
} | |
func MakeLogger(logLevel string) log.Logger { | |
logger := log.NewJSONLogger(log.NewSyncWriter(os.Stdout)) | |
switch logLevel { | |
case "error": | |
logger = level.NewFilter(logger, level.AllowError()) | |
case "warn": | |
logger = level.NewFilter(logger, level.AllowWarn()) | |
case "debug": | |
logger = level.NewFilter(logger, level.AllowDebug()) | |
default: | |
logger = level.NewFilter(logger, level.AllowInfo()) | |
} | |
logger = log.With(logger, "ts", log.DefaultTimestampUTC) | |
logger = level.NewInjector(logger, level.InfoValue()) | |
return logger | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment