1、啟動
啟動例子:
// 創建的時候會加載默認配置
service := micro.NewService()
// 初始化配置,這里可以添加配置,或從flags中覆蓋默認配置
service.Init()
// 注冊服務
hello.RegisterSayHandler(service.Server(), new(Say))
// 啟動
if err := service.Run(); err != nil {
log.Fatal(err)
}
1.1、默認配置
func newOptions(opts ...Option) Options {
opt := Options{
Broker: broker.DefaultBroker,
Cmd: cmd.DefaultCmd,
Client: client.DefaultClient,
Server: server.DefaultServer,
Registry: registry.DefaultRegistry,
Transport: transport.DefaultTransport,
Context: context.Background(),
}
for _, o := range opts {
o(&opt)
}
return opt
}
所有默認服務
DefaultBroker Broker = newHttpBroker()
DefaultCmd = newCmd()
DefaultClient Client = newRpcClient()
DefaultRegistry = newConsulRegistry()
DefaultTransport Transport = newHTTPTransport()
DefaultSelector = newDefaultSelector() // Strategy: Random,
DefaultServer Server = newRpcServer()
服務器端啟動流程
1、opts.BeforeStart 事件觸發
2、opts.Server.Start() 開啟server服務,go ts.Accept監聽端口請求,會注冊一個debugHandler提供Health,Stats方法,config.Broker.Connect()
3、opts.Server.Register() 注冊服務到服務發現
4、opts.AfterStart 事件觸發
5、go opts.Server.Register() 定時注冊服務到服務發現
6、signal.Notify 監聽signal退出
7、opts.BeforeStop 事件觸發
8、opts.Server.Deregister() 從服務發現中剔除
9、opts.Server.Stop() 觸發服務端退出ch, 等待請求結束,關閉Transport,Broker.Disconnect()
10、opts.AfterStop 事件觸發
連接處理函數
func (s *rpcServer) accept(sock transport.Socket) {
defer func() {
// close socket
sock.Close()
if r := recover(); r != nil {
log.Log("panic recovered: ", r)
log.Log(string(debug.Stack()))
}
}()
for {
var msg transport.Message // 取message
if err := sock.Recv(&msg); err != nil {
return
}
// we use this Timeout header to set a server deadline
to := msg.Header["Timeout"]
// we use this Content-Type header to identify the codec needed
ct := msg.Header["Content-Type"]
cf, err := s.newCodec(ct) // 初始化decoder
// TODO: needs better error handling
if err != nil {
sock.Send(&transport.Message{
Header: map[string]string{
"Content-Type": "text/plain",
},
Body: []byte(err.Error()),
})
return
}
codec := newRpcPlusCodec(&msg, sock, cf) // sock用于寫錯誤
// strip our headers
hdr := make(map[string]string)
for k, v := range msg.Header {
hdr[k] = v
}
delete(hdr, "Content-Type")
delete(hdr, "Timeout")
ctx := metadata.NewContext(context.Background(), hdr)
// set the timeout if we have it
if len(to) > 0 {
if n, err := strconv.ParseUint(to, 10, 64); err == nil {
ctx, _ = context.WithTimeout(ctx, time.Duration(n))
}
}
// add to wait group
s.wg.Add(1)
defer s.wg.Done()
// TODO: needs better error handling 調用對應service方法
if err := s.rpc.serveRequest(ctx, codec, ct); err != nil {
log.Logf("Unexpected error serving request, closing socket: %v", err)
return
}
}
}