github.com/go-srvc/srvc
go get github.com/go-srvc/srvc@v0.1.0
README
Simple, Safe, and Modular Service Runner
srvc library provides a simple but powerful interface with zero external dependencies for running service modules.
Use Case
Usually, Go services are composed of multiple "modules" which runs each in their own goroutine such as http server, signal listener, kafka consumer, ticker, etc. These modules should remain alive throughout the lifecycle of the whole service, and if one goes down, gracefully exit should be executed to avoid "zombie" services. srvc takes care of all this via a simple module interface. List of ready made modules can be found under github.com/go-srvc/mods
Usage
Basic main usage:
package main
import (
"fmt"
"net/http"
"os"
"github.com/go-srvc/mods/httpmod"
"github.com/go-srvc/mods/logmod"
"github.com/go-srvc/mods/metermod"
"github.com/go-srvc/mods/sigmod"
"github.com/go-srvc/mods/sqlxmod"
"github.com/go-srvc/mods/tracemod"
"github.com/go-srvc/srvc"
)
func main() {
db := sqlxmod.New()
srvc.RunAndExit(
sigmod.New(os.Interrupt),
logmod.New(),
tracemod.New(),
metermod.New(),
db,
httpmod.New(
httpmod.WithHandler(
handler(db),
),
),
)
}
func handler(db *sqlxmod.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := db.DB().PingContext(r.Context()); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprint(w, "OK")
})
}
Implementing custom modules
package main
import (
"github.com/go-srvc/srvc"
)
type MyMod struct {
done chan struct{}
}
func (m *MyMod) Init() error {
m.done = make(chan struct{})
return nil
}
// Run should block until the module is stopped.
// If you don't have a blocking operation, you can use done channel to block.
func (m *MyMod) Run() error {
<-m.done
return nil
}
func (m *MyMod) Stop() error {
defer close(m.done)
return nil
}
func (m *MyMod) ID() string { return "MyMod" }
func main() {
srvc.RunAndExit(
&MyMod{},
)
}
Acknowledgements
This library is something I have found myself writing over and over again in every project I been part of. One of the iterations can be found under https://github.com/elisasre/go-common.
Overview
Package srvc provides simple but powerful Run functionality on top of Module abstraction. Ready made modules can be found under: github.com/go-srvc/mods.
Constants
const ErrModulePanic = ErrStr("module recovered from panic")Variables
var JoinErrors = errors.JoinJoinErrors allows overwriting the default errors.JoinErrors function used by srvc package. This can be useful for custom multi error formatting.
Functions
func Run
func Run(modules ...Module) errorRun will run all given modules using following control flow:
- Exec Init() for each module in order. If any Init() returns error the Init loop is stopped and Stop() will be called for already initialized modules in reverse order.
- Exec Run() for each module in own goroutine so order isn't guaranteed.
- Wait for any Run() function to return nil or an error and move to Stop loop.
- Exec Stop() for modules in reverse order.
- Wait for all Run() goroutines to return.
- Return all errors or nil
Possible panics inside modules are captured to allow graceful shutdown of other modules. Captured panics are converted into errors and ErrPanic is returned.
func RunAndExit
func RunAndExit(modules ...Module)RunAndExit is convenience wrapper for Run that calls os.Exit with code 1 in case of an error. The common use case is to srvc.RunAndExit from main function and let the srvc handle the rest.
package main
import "github.com/go-srvc/srvc"
func main() {
srvc.RunAndExit(
// Add your modules here
)
}
Types
type ErrGroup
type ErrGroup struct {
// contains filtered or unexported fields
}ErrGroup is a goroutine group that waits for all goroutines to finish and collects errors.
func (*ErrGroup) Go
func (eg *ErrGroup) Go(f func() error)Go runs the given function in a goroutine.
func (*ErrGroup) Wait
func (eg *ErrGroup) Wait() errorWait waits for all goroutines to finish and returns all errors that occurred.
type ErrStr
type ErrStr stringErrStr adds Error method to string type.
func (ErrStr) Error
func (e ErrStr) Error() stringtype Module
type Module interface {
// ID should return identifier for logging purposes.
ID() string
// Init allows synchronous initialization of module.
Init() error
// Run should start the module and block until stop is called or error occurs.
Run() error
// Stop allows synchronous cleanup of module should make Run() return eventually.
// If Init was called then Stop is guaranteed to be called as part of cleanup.
Stop() error
}