initial import
This commit is contained in:
56
core/service/serviceconf.go
Normal file
56
core/service/serviceconf.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"zero/core/load"
|
||||
"zero/core/logx"
|
||||
"zero/core/prometheus"
|
||||
"zero/core/stat"
|
||||
)
|
||||
|
||||
const (
|
||||
DevMode = "dev"
|
||||
TestMode = "test"
|
||||
PreMode = "pre"
|
||||
ProMode = "pro"
|
||||
)
|
||||
|
||||
type ServiceConf struct {
|
||||
Name string
|
||||
Log logx.LogConf
|
||||
Mode string `json:",default=pro,options=dev|test|pre|pro"`
|
||||
MetricsUrl string `json:",optional"`
|
||||
Prometheus prometheus.Config `json:",optional"`
|
||||
}
|
||||
|
||||
func (sc ServiceConf) MustSetUp() {
|
||||
if err := sc.SetUp(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (sc ServiceConf) SetUp() error {
|
||||
if len(sc.Log.ServiceName) == 0 {
|
||||
sc.Log.ServiceName = sc.Name
|
||||
}
|
||||
if err := logx.SetUp(sc.Log); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sc.initMode()
|
||||
prometheus.StartAgent(sc.Prometheus)
|
||||
if len(sc.MetricsUrl) > 0 {
|
||||
stat.SetReportWriter(stat.NewRemoteWriter(sc.MetricsUrl))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sc ServiceConf) initMode() {
|
||||
switch sc.Mode {
|
||||
case DevMode, TestMode, PreMode:
|
||||
load.Disable()
|
||||
stat.SetReporter(nil)
|
||||
}
|
||||
}
|
||||
107
core/service/servicegroup.go
Normal file
107
core/service/servicegroup.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"zero/core/proc"
|
||||
"zero/core/syncx"
|
||||
"zero/core/threading"
|
||||
)
|
||||
|
||||
type (
|
||||
Starter interface {
|
||||
Start()
|
||||
}
|
||||
|
||||
Stopper interface {
|
||||
Stop()
|
||||
}
|
||||
|
||||
Service interface {
|
||||
Starter
|
||||
Stopper
|
||||
}
|
||||
|
||||
ServiceGroup struct {
|
||||
services []Service
|
||||
stopOnce func()
|
||||
}
|
||||
)
|
||||
|
||||
func NewServiceGroup() *ServiceGroup {
|
||||
sg := new(ServiceGroup)
|
||||
sg.stopOnce = syncx.Once(sg.doStop)
|
||||
return sg
|
||||
}
|
||||
|
||||
func (sg *ServiceGroup) Add(service Service) {
|
||||
sg.services = append(sg.services, service)
|
||||
}
|
||||
|
||||
// There should not be any logic code after calling this method, because this method is a blocking one.
|
||||
// Also, quitting this method will close the logx output.
|
||||
func (sg *ServiceGroup) Start() {
|
||||
proc.AddShutdownListener(func() {
|
||||
log.Println("Shutting down...")
|
||||
sg.stopOnce()
|
||||
})
|
||||
|
||||
sg.doStart()
|
||||
}
|
||||
|
||||
func (sg *ServiceGroup) Stop() {
|
||||
sg.stopOnce()
|
||||
}
|
||||
|
||||
func (sg *ServiceGroup) doStart() {
|
||||
routineGroup := threading.NewRoutineGroup()
|
||||
|
||||
for i := range sg.services {
|
||||
service := sg.services[i]
|
||||
routineGroup.RunSafe(func() {
|
||||
service.Start()
|
||||
})
|
||||
}
|
||||
|
||||
routineGroup.Wait()
|
||||
}
|
||||
|
||||
func (sg *ServiceGroup) doStop() {
|
||||
for _, service := range sg.services {
|
||||
service.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func WithStart(start func()) Service {
|
||||
return startOnlyService{
|
||||
start: start,
|
||||
}
|
||||
}
|
||||
|
||||
func WithStarter(start Starter) Service {
|
||||
return starterOnlyService{
|
||||
Starter: start,
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
stopper struct {
|
||||
}
|
||||
|
||||
startOnlyService struct {
|
||||
start func()
|
||||
stopper
|
||||
}
|
||||
|
||||
starterOnlyService struct {
|
||||
Starter
|
||||
stopper
|
||||
}
|
||||
)
|
||||
|
||||
func (s stopper) Stop() {
|
||||
}
|
||||
|
||||
func (s startOnlyService) Start() {
|
||||
s.start()
|
||||
}
|
||||
126
core/service/servicegroup_test.go
Normal file
126
core/service/servicegroup_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
number = 1
|
||||
mutex sync.Mutex
|
||||
done = make(chan struct{})
|
||||
)
|
||||
|
||||
type mockedService struct {
|
||||
quit chan struct{}
|
||||
multiplier int
|
||||
}
|
||||
|
||||
func newMockedService(multiplier int) *mockedService {
|
||||
return &mockedService{
|
||||
quit: make(chan struct{}),
|
||||
multiplier: multiplier,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *mockedService) Start() {
|
||||
mutex.Lock()
|
||||
number = number * s.multiplier
|
||||
mutex.Unlock()
|
||||
done <- struct{}{}
|
||||
<-s.quit
|
||||
}
|
||||
|
||||
func (s *mockedService) Stop() {
|
||||
close(s.quit)
|
||||
}
|
||||
|
||||
func TestServiceGroup(t *testing.T) {
|
||||
multipliers := []int{2, 3, 5, 7}
|
||||
want := 1
|
||||
|
||||
group := NewServiceGroup()
|
||||
for _, multiplier := range multipliers {
|
||||
want *= multiplier
|
||||
service := newMockedService(multiplier)
|
||||
group.Add(service)
|
||||
}
|
||||
|
||||
go group.Start()
|
||||
|
||||
for i := 0; i < len(multipliers); i++ {
|
||||
<-done
|
||||
}
|
||||
|
||||
group.Stop()
|
||||
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
assert.Equal(t, want, number)
|
||||
}
|
||||
|
||||
func TestServiceGroup_WithStart(t *testing.T) {
|
||||
multipliers := []int{2, 3, 5, 7}
|
||||
want := 1
|
||||
|
||||
var wait sync.WaitGroup
|
||||
var lock sync.Mutex
|
||||
wait.Add(len(multipliers))
|
||||
group := NewServiceGroup()
|
||||
for _, multiplier := range multipliers {
|
||||
var mul = multiplier
|
||||
group.Add(WithStart(func() {
|
||||
lock.Lock()
|
||||
want *= mul
|
||||
lock.Unlock()
|
||||
wait.Done()
|
||||
}))
|
||||
}
|
||||
|
||||
go group.Start()
|
||||
wait.Wait()
|
||||
group.Stop()
|
||||
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
assert.Equal(t, 210, want)
|
||||
}
|
||||
|
||||
func TestServiceGroup_WithStarter(t *testing.T) {
|
||||
multipliers := []int{2, 3, 5, 7}
|
||||
want := 1
|
||||
|
||||
var wait sync.WaitGroup
|
||||
var lock sync.Mutex
|
||||
wait.Add(len(multipliers))
|
||||
group := NewServiceGroup()
|
||||
for _, multiplier := range multipliers {
|
||||
var mul = multiplier
|
||||
group.Add(WithStarter(mockedStarter{
|
||||
fn: func() {
|
||||
lock.Lock()
|
||||
want *= mul
|
||||
lock.Unlock()
|
||||
wait.Done()
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
go group.Start()
|
||||
wait.Wait()
|
||||
group.Stop()
|
||||
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
assert.Equal(t, 210, want)
|
||||
}
|
||||
|
||||
type mockedStarter struct {
|
||||
fn func()
|
||||
}
|
||||
|
||||
func (s mockedStarter) Start() {
|
||||
s.fn()
|
||||
}
|
||||
Reference in New Issue
Block a user