Build Gobs service
A service instance managed by gobs has 4 stages of its lifecycle: init, setup, start, stop. Users can optionally custom those step for particular services. Let’s go to functionalities of each stages
Init service
Initialization stage is used for setting up dependencies of a service.
type API struct {
log *log.Log
cfg *conf.Config
}
var _ gobs.InitService = (*API)(nil)
// set dependencies of API are log.Log and conf.Config
func (a *API) Init(ctx context.Context) (*gobs.ServiceLifeCycle, error) {
return gobs.GenerateSetupConfig(&a.log, &a.cfg)
}type API struct {
log *log.Log
cfg *conf.Config
}
var _ gobs.InitService = (*API)(nil)
// set dependencies of API are log.Log and conf.Config
func (a *API) Init(ctx context.Context) (*gobs.ServiceLifeCycle, error) {
return &gobs.ServiceLifeCycle{
Deps: []interface{
&log.Log{},
&conf.Config{},
},
OnSetup: func(ctx context.Context, deps Dependencies) error {
return deps.Assign(&a.log, &a.cfg)
}
}, nil
}type API struct {
log *log.Log
cfg *conf.Config
}
var _ gobs.InitService = (*API)(nil)
// set dependencies of API are log.Log and conf.Config
// and the conf.Config is different from common shared conf.Config
func (a *API) Init(ctx context.Context) (*gobs.ServiceLifeCycle, error) {
return &gobs.ServiceLifeCycle{
Deps: []interface{
&log.Log{},
},
ExtraDeps: []gobs.CustomService{
Name: "Configuration 2",
Service: &conf.Config{},
},
OnSetup: func(ctx context.Context, deps Dependencies) error {
a.log = deps[0]
a.cfg = deps[1]
}
}, nil
}With the configuration above, API service depends on 2 services: Log and Config. At init stage, gobs will try to find instances of Log and Config in gobs sharing pool to return as deps parameter on OnSetup callback.
All next stages of API service will follow the dependencies set up at init stage.
Setup service
Setup stage is used for configuring of a service before starting.
type API struct {
log *log.Log
cfg *conf.Config
}
var _ gobs.SetupService = (*API)(nil)
func (a *API) Setup(ctx context.Context) error {
a.log.Info("API is setup")
return a.cfg.Config()
}When API implements method Setup like gobs.SetupService, gobs will manage to run a.Setup after log.Log and conf.Config finish their Setup.
log.Log or conf.Config failed in running Setup, the setup process will stop immediately and Setup of API won’t be invokedStart service
Start stage is used for running main process of a service.
type API struct {
log *log.Log
cfg *conf.Config
}
var _ gobs.StartService = (*API)(nil)
func (a *API) Start(ctx context.Context) error {
a.log.Info("API is running")
return a.Run()
}When API implements method Start like gobs.StartService, gobs will manage to run a.Start after log.Log and conf.Config finish their Start
log or cfg is pending without finishing Start methodlog.Log or conf.Config failed in running Setup, the setup process will stop immediately and Setup of API won’t be invokedStop service
Start stage is used to do the last execution and release resources before existing the application.
type API struct {
log *log.Log
cfg *conf.Config
}
var _ gobs.StopService = (*API)(nil)
func (a *API) Stop(ctx context.Context) {
a.log.Info("API is stopped")
a.cfg.Release()
}Stop flow is in reverse order to Setup and Start flow. Setup method of conf.Config and log.Log will be called after Stop of API finish its works. gobs only invoke Stop of the services which had finished their Setup stage.
Stop process will run automatically if Setup or Start failComplete
type API struct {
log *log.Log
cfg *conf.Config
}
var _ gobs.InitService = (*API)(nil)
func (a *API) Init(ctx context.Context) (*gobs.ServiceLifeCycle, error) {
return gobs.GenerateSetupConfig(&a.log, &a.cfg)
}
var _ gobs.SetupService = (*API)(nil)
func (a *API) Setup(ctx context.Context) error {
a.log.Info("API is setup")
return a.cfg.Config()
}
var _ gobs.StartService = (*API)(nil)
func (a *API) Start(ctx context.Context) error {
a.log.Info("API is running")
return a.Run()
}
var _ gobs.StopService = (*API)(nil)
func (a *API) Stop(ctx context.Context) {
a.log.Info("API is stopped")
a.cfg.Release()
}Bonus
If your service is simple you can ignore Init method and setup your instance as common pattern below
type API struct {
log *log.Log
cfg *conf.Config
}
func NewAPI(log *log.Log, cfg *conf.Config) *API {
return &API{
log: log,
cfg: cfg,
}
}
var _ gobs.SetupService = (*API)(nil)
func (a *API) Setup(ctx context.Context) error {
a.log.Info("API is setup")
return a.cfg.Config()
}
var _ gobs.StartService = (*API)(nil)
func (a *API) Start(ctx context.Context) error {
a.log.Info("API is running")
return a.Run()
}
var _ gobs.StopService = (*API)(nil)
func (a *API) Stop(ctx context.Context) {
a.log.Info("API is stopped")
a.cfg.Release()
}Then the creation of gobs instance will be
func main() {
ctx := context.Background()
bs := gobs.NewBootstrap()
cfg := NewConfig()
log := NewLog()
api := NewAPI(log, cfg)
bs.AddOrPanic(cfg)
bs.AddOrPanic(log)
bs.AddOrPanic(api)
bs.Start(ctx)
}