protocol

package
v0.0.0-...-8c4fe33 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 29, 2023 License: MIT Imports: 15 Imported by: 0

README

对外暴露协议的方案

HTTP服务

  1. 启动方法

核心就是去监听HTTP服务的端口


// Start 开启服务
func (s *HttpService) Start() error {
    
    // 调用执行前的逻辑
    if err := s.before.Before(s); err != nil {
        s.L.Errorf("Start前的逻辑执行失败")
        return err
    }
    
    s.L.Infof("[HTTP] 服务监听地址:%s", s.C.App.HTTP.Addr())
    if err := s.server.ListenAndServe(); err != nil {
        // 如果错误是正常关闭,则不报错
        if err == http.ErrServerClosed {
            s.L.Infof("服务 stop 成功")
            return nil
        }
	    return fmt.Errorf("开启 [HTTP] 服务异常:%s", err.Error())
    }
    
    return nil
}
  1. 优雅关闭

什么时优雅关闭?为什么需要优雅关闭?

优雅关闭就是当程序监听到一些信号,会导致程序进程退出时,会像优雅的谦谦君子一样,做好退出的提示和善后

至于为什么要优雅关闭。除了友好的提示。最主要的还是因为:

比如有几个串行访问的请求,他们已经发送出来了,但是这个时候程序遇到了一些紧急关闭信号。

如果没有优雅关闭,已经发出来的请求,会得不到处理,程序就会退出。程序就会崩溃。很像不负责的渣男!!!

但如果有优雅关闭,当接收到关闭信号时,它大致会做两件事情:

  • 关闭新请求的通道,保证不会有新的请求进来
  • 处理完已发送的请求,做一个负责的男人
func (s *HttpService) Stop() error {
	s.L.Infof("服务开始 stop")
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	if err := s.server.Shutdown(ctx); err != nil {
		s.L.Warnf("关闭服务异常:%s", err)
		return err
	}
	return nil
}

GRPC服务

  1. 启动(监听GRPC服务所需的TCP端口)、优雅关闭
func (s *GRPCService) Start() {
	// =====
	// 1、注册IOC中所有的GRPC服务
	// =====
	ioc.RegistryGrpc(s.server)

	// =====
	// 2、启动GRPC服务
	// =====
	addr := s.cfg.App.GRPC.Addr()
	listener, err := net.Listen("tcp", addr)
	s.l.Infof("[GRPC] 服务监听地址:%s", addr)
	if err != nil {
		s.l.Errorf("启动GRPC服务错误:%s", err.Error())
		return
	}

	// 理论上我们需要等待GRPC服务启动成功后,才注册此服务到注册中心
	// 但是 GRPC Server 并没有什么成功的回调通知

	// 所以我们只能假设GRPC Server 1秒后启动成功
	time.AfterFunc(1*time.Second, s.Register)

	// 注册服务开启健康检查
	grpc_health_v1.RegisterHealthServer(s.server, health.NewServer())

	// =====
	// 3、监听GRPC服务
	// =====
	if err = s.server.Serve(listener); err != nil {
		if err == grpc.ErrServerStopped {
			s.l.Infof("[GRPC] 服务关闭成功")
		}
		s.l.Errorf("开启 [GRPC] 服务异常:%s", err.Error())
		return
	}

}

// Stop 优雅关闭GRPC服务
func (s *GRPCService) Stop() error {
	s.l.Infof("优雅关闭 [GRPC] 服务")
	// 注销在consul中的 GRPC 服务
	s.DeRegister()
	s.server.GracefulStop()
	return nil
}
  1. 服务注册到注册中心

既然是微服务,需要走RPC调用,肯定需要服务发现和服务注册的注册中心,(我们这里是Consul)

那么,是如何注册服务到Consul的呢、当退出时,又是如何注销服务的呢?

核心就是通过Consul的配置文件,拿到Consul的客户端。用Client提供的SDK,管理注册和退出。

注册时需要:实例化健康检查对象、注册对象

注销时需要:提供待注销服务注册时的ID

func (s *GRPCService) Register() {

	// 生成对应grpc的检查对象
	check := &api.AgentServiceCheck{
		GRPC:                           s.cfg.App.GRPC.Addr(),
		Timeout:                        "5s",
		Interval:                       "5s",
		DeregisterCriticalServiceAfter: "15s",
	}

	consul := s.cfg.Consul

	// 生成注册对象
	registration := new(api.AgentServiceRegistration)
	registration.Name = consul.Register.RegistryName
	registration.ID = xid.New().String()
	registration.Port = s.cfg.App.GRPC.Port
	registration.Tags = consul.Register.Tags
	registration.Address = s.cfg.App.GRPC.Host
	registration.Check = check

	err := s.client.Agent().ServiceRegister(registration)
	if err != nil {
		s.l.Errorf("注册GRPC服务到consul失败:%s", err)
		return
	}

	s.registration = registration
	s.l.Info("成功注册GRPC服务到consul")
}

// 服务注销
func (s *GRPCService) DeRegister() {
    if s.registration != nil {
        err := s.client.Agent().ServiceDeregister(s.registration.ID)
        if err != nil {
            s.l.Errorf("注销实例失败:%s", err)
        } else {
        s.l.Info("注销实例成功")
        }
    }
}

怎么利用AOP(面向切面编程)的思想抽取成公共代码了?

因为抽取到公共库里面了。为了使其他逻辑通用。利用了切面的方式,可供外界在启动前执行一些逻辑。

当然,你还可以定义执行后的切面...

比如:HTTP在启动前,我这里做了一个启动前的切面,并且提供了默认切面:

    // 调用执行前的逻辑
	if err := s.before.Before(s); err != nil {
		s.L.Errorf("Start前的逻辑执行失败")
		return err
	}

// DefaultHttpStartBefore 返回一个默认的切面:HTTPStartBefore
func DefaultHttpStartBefore() StartFuncAop {
    return func(s *HttpService) error {
        // 1、将所有的Gin服务对象注册到IOC中
        option := ioc.NewGinOption(s.R, "/"+s.C.App.Name)
        ioc.RegistryGin(option)
        return nil
    }
}

在外界使用时:若无特殊处理逻辑,直接使用默认的Before切面即可。 但若有特殊逻辑,如video_service:添加了部分中间件,

	cmd.HttpStartAop = func(s *protocol.HttpService) error {
		// 1、获取中间件
		mids, err := getMiddle()
		if err != nil {
			return err
		}
		// 2、将所有的Gin服务对象注册到IOC中
		option := ioc.NewGinOption(s.R, "/"+s.C.App.Name, mids...)
		option.NotVersion = true
		option.NotName = true
		ioc.RegistryGin(option)
		return nil
	}

Documentation

Overview

@Author: Ciusyan 2023/2/10

@Author: Ciusyan 2023/2/10

@Author: Ciusyan 2023/1/25

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type GRPCService

type GRPCService struct {
	// contains filtered or unexported fields
}

func NewGRPCService

func NewGRPCService() *GRPCService

func (*GRPCService) DeRegister

func (s *GRPCService) DeRegister()

DeRegister 注销在Consul的GRPC服务

func (*GRPCService) Register

func (s *GRPCService) Register()

Register 注册GRPC服务到consul

func (*GRPCService) Start

func (s *GRPCService) Start()

Start 启动GRPC服务

func (*GRPCService) Stop

func (s *GRPCService) Stop() error

Stop 优雅关闭GRPC服务

type HttpService

type HttpService struct {
	L logger.Logger // 用于打印日志
	R gin.IRouter
	C *conf.Config // 用于获取项目名称
	// contains filtered or unexported fields
}

func NewHttpService

func NewHttpService(f StartFuncAop) *HttpService

func (*HttpService) Start

func (s *HttpService) Start() error

Start 开启服务

func (*HttpService) Stop

func (s *HttpService) Stop() error

Stop 停止服务

type StartFuncAop

type StartFuncAop func(*HttpService) error

StartFuncAop 用于执行前的逻辑

func DefaultHttpStartBefore

func DefaultHttpStartBefore() StartFuncAop

DefaultHttpStartBefore 返回一个默认的切面:HTTPStartBefore

func (StartFuncAop) After

func (f StartFuncAop) After(h *HttpService) error

After 用于执行后,切入代码

func (StartFuncAop) Before

func (f StartFuncAop) Before(h *HttpService) error

Before 用于执行前,切入代码

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL