code
好的代码忍不住想记2笔。重点拿来即用
- 服务管理。服务启动按此套路来,初始化,启动,停止的轮廓感特强,借鉴nsqd。
package main
import (
"github.com/judwhite/go-svc/svc"
"github.com/rs/zerolog/log"
"sync"
)
type program struct {
once sync.Once
}
//服务未开始需要准备的工作
func (p *program) Init(env svc.Environment) error {
return nil
}
//服务启动的业务代码入口
func (p *program) Start() error {
return nil
}
//当你的服务进程被kill pid 的时候会触动Stop方法执行,stop执行完毕进程退出(当然kill -9 pid是不行的)
func (p *program) Stop() error {
//once是避免多次kill发送过来停止信号
p.once.Do(func() {
})
return nil
}
func main() {
prg := &program{}
if err := svc.Run(prg); err != nil {
}
}
- 并发型却相互依赖goroutinu。任意一个协程error了,外围便知,亮点的code结构上干净利落的解耦,却又能轻易做到紧密通讯。nsqd使用此设计 控制http,tcp,https等服务启动到停止的生命周期。
package main
import (
"sync"
)
type WaitGroupWrapper struct {
sync.WaitGroup
}
func (w *WaitGroupWrapper) Wrap(cb func()) {
w.Add(1)
go func() {
cb()
w.Done()
}()
}
func main(){
w := WaitGroupWrapper{}
exitCh := make(chan error)
var once sync.Once
exitFunc := func(err error) {
once.Do(func() {
if err != nil {
fmt.Println("自定义打印日志")
}
exitCh <- err
})
}
//TCPServer,TCPServer(),HttpServer() 假装是一个个协程相互独立并行却同时正常才行的协程
// 当然TCPServer,HttpServer需要保证 能被通讯到
w.waitGroup.Wrap(func() {
exitFunc(TCPServer())
})
w.waitGroup.Wrap(func() {
exitFunc(HttpServer())
})
err := <-exitCh
fmt.Println("err到说明存在服务err了,在此开始你的err错误处理逻辑,保证业务代码从上而下顺流而下")
return
}
- 协程编排。让你能轻松设计出系列串行goroutinue,和并行goroutinue,其表现规则在代码结构层也清晰易懂,有异常捕获。
package main
import (
"errors"
"fmt"
"runtime"
"sync"
)
func try(fn func(), cleaner func()) (err error) {
if cleaner != nil {
defer cleaner()
}
defer func() {
_, file, line, _ := runtime.Caller(2)
if rErr := recover(); rErr != nil {
if _, ok := rErr.(error); ok {
err = errors.New(fmt.Sprintf("%s:%d,err:%v", file, line,rErr.(error)))
} else {
err = fmt.Errorf("%+v", rErr)
}
}
}()
fn()
return nil
}
// Parallel 并发执行
func Parallel(fns ...func()) func() {
var wg sync.WaitGroup
return func() {
wg.Add(len(fns))
for _, fn := range fns {
go try(fn, wg.Done)
}
wg.Wait()
}
}
// Serial 串行
func Serial(fns ...func()) func() {
return func() {
for _, fn := range fns {
fn()
}
}
}
func main() {
serial1 := func() {
fmt.Println("我是串行协程1")
}
parallels := Parallel(
func(){
fmt.Println("我是并行协程1,我得等到 serial1 里面的串行协程执行完毕后才能执行")
},
func(){
fmt.Println("我是并行协程2,我得等到 serial1 里面的串行协程执行完毕后才能执行")
},
)
serial4 := func() {
fmt.Println("我是串行协程4,我得等到 Parallel 里面的2并发协程都执行完毕才能开始")
}
run :=Serial(serial1,parallels,serial4)
//开跑
run()
}