golang微服务框架go-micro使用 (六) Config And Errors

司空镜
2023-12-01

Config

特征

  • 1 动态加载:根据需要动态加载多个资源文件。 go config 在后台管理并监控配置文件,并自动更新到内存中
  • 2 资源可插拔: 从任意数量的源中进行选择以加载和合并配置。后台资源源被抽象为内部使用的标准格式,并通过编码器进行解码。源可以是环境变量,标志,文件,etcd,k8s configmap等
  • 3 可合并的配置:如果指定了多种配置,它们会合并到一个视图中。
  • 4 监控变化:可以选择是否监控配置的指定值,热重启
  • 5 安全恢复: 万一配置加载错误或者由于未知原因而清除,可以指定回退值进行回退

Sources

Source 是资源加载来源,支持以下形式:

  • cli 命令行
  • consul
  • env
  • etcd
  • file
  • flag
  • memory
    也有一些社区支持的插件:
  • configmap - nread from k8s configmap
  • grpc - read from grpc server
  • runtimevar - read from Go Cloud Development Kit runtime variable
  • url - read from URL
  • vault - read from Vault server

ChangeSet

Source返回ChangeSet,是多个后端的单例内部抽象

// ChangeSet represents a set of changes from a source
type ChangeSet struct {
	// Raw encoded config data
	Data      []byte
	// MD5 checksum of the data
	Checksum  string
	// Encoding format e.g json, yaml, toml, xml
	Format    string
	// Source of the config e.g file, consul, etcd
	Source    string
	// Time of loading or update
	Timestamp time.Time
}

Encoder

Encoder 处理配置文件的编码与解码,支持:

  • json
  • yaml
  • toml
  • xml
  • xml
  • hcl

Config

// Config is an interface abstraction for dynamic configuration
type Config interface {
        // provide the reader.Values interface
        reader.Values
	// Stop the config loader/watcher
	Close() error
	// Load config sources
	Load(source ...source.Source) error
	// Force a source changeset sync
	Sync() error
	// Watch a value for changes
	Watch(path ...string) (Watcher, error)
}

示例

在项目中创建config目录,加入文件conf.go 与 db.toml
db.toml

[myslq]
host = "127.0.0.3"
port = 3306

conf.go

package config

import (
	"github.com/micro/go-micro/v2/config"
	"github.com/micro/go-micro/v2/config/encoder/toml"
	"github.com/micro/go-micro/v2/config/source"
	"github.com/micro/go-micro/v2/config/source/file"
)

func init()  {
	enc := toml.NewEncoder()

	// Load toml file with encoder
	config.Load(
		file.NewSource(
			file.WithPath("/home/luslin/go/workspace/tools/micro-hello/config/db.toml"),
			source.WithEncoder(enc),
		),
	)
}

main.go 中加入

import _ "micro-hello/config"
	go func() {
		for range time.Tick(time.Second) {
			conf := config.Map()
			fmt.Println(conf)
		}
	}()

在运行时更改db.toml 文件,就可以看到值的变化

Errors

error type:

type Error struct {
	Id                   string   `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
	Code                 int32    `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"`
	Detail               string   `protobuf:"bytes,3,opt,name=detail,proto3" json:"detail,omitempty"`
	Status               string   `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

使用

handler/micro.go

// Call is a single request handler called via client.Call or the generated client code
func (e *Micro) Call(ctx context.Context, req *hello.Request, rsp *hello.Response) error {
	log.Info("Received Micro.Call request")
	rsp.Msg = "Hello " + req.Name
	return errors.BadRequest("com.foo.service.hello.Call", "invalid field")
}

使用 micro web 或前面的mico-hello-cli 项目调用接口

func main() {
	// New Service
	service := micro.NewService(
		micro.Name("com.foo.service.micro.clinet"),
		micro.Version("latest"),
	)
	service.Init()
	resp,err := hello.NewMicroService("com.foo.service.micro",service.Client()).Call(context.TODO(),&hello.Request{Name: "lin"})
	if err != nil {
		e := errors.Parse(err.Error())
		fmt.Println(e)
		os.Exit(1)
	}

	fmt.Println(resp.Msg)
}

结果:

{"id":"com.foo.service.hello.Call","code":400,"detail":"invalid field","status":"Bad Request"}

类别

  • BadRequest
  • Unauthorized
  • Forbidden
  • NotFound
  • MethodNotAllowed
  • Timeout
  • Conflict
  • InternalServerError
    如果默认的这些不满足要求,可以使用New创建
// New generates a custom error.
func New(id, detail string, code int32) error {
	return &Error{
		Id:     id,
		Code:   code,
		Detail: detail,
		Status: http.StatusText(int(code)),
	}
}
 类似资料: