# luca
**Repository Path**: woood2/luca
## Basic Information
- **Project Name**: luca
- **Description**: 一个支持多入口、开箱即用的企业级Golang框架
- **Primary Language**: Go
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-10-05
- **Last Updated**: 2026-04-24
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
### 概述
LUCA Enterprise Framework(简称luca)是一款支持多入口、开箱即用的企业级Golang框架。
在设计哲学上,luca更接近于 [整洁架构](https://book.douban.com/subject/30333919/) ,而非 [Spring](https://spring.io/) 这种包办一切的大管家。
- 支持4种作业类型:Restful服务、微服务、定时任务、队列消费。
- 配套设施整合:注册/配置中心、链路追踪、日志收集、指标监控、熔断器、API文档。
- 程序设计实践:错误处理、分层、依赖注入、数据库、缓存、多环境、优雅关闭、灰度发布、单元测试。

### 初始化
```
wget https://gitee.com/woood2/luca/raw/master/scripts/gen.sh
chmod +x ./gen.sh
./gen.sh
```
### 目录结构
luca的目录规划遵循 [社区规范](https://github.com/golang-standards/project-layout/blob/master/README_zh.md) 建议的风格
```
├── cmd
│ ├── backend
│ ├── consumer
│ ├── cron
│ └── micro
├── configs
├── deployments
├── docs
├── internal
│ ├── cache
│ ├── conf
│ ├── db
│ ├── debugger
│ ├── discovery
│ ├── layer
│ ├── log
│ ├── mq
│ ├── producer
│ ├── repository
│ ├── sdk
│ ├── service
│ ├── status
│ ├── trace
│ ├── util
│ └── wrong
├── scripts
└── test
│ ├── doctor
│ └── grpc_client
```
### 多入口
[cmd/](https://gitee.com/woood2/luca/tree/master/cmd) 默认拥有4个子目录,对应4个入口、4种作业类型。
```
├── cmd
│ ├── backend Restful服务
│ │ ├── docs
│ │ ├── internal
│ │ ├── main.go
│ │ └── swag.sh
│ ├── consumer 队列消费
│ │ ├── internal
│ │ └── main.go
│ ├── cron 定时任务
│ │ ├── internal
│ │ └── main.go
│ └── micro 微服务
│ ├── internal
│ ├── pkg
│ └── main.go
```
入口专用的代码存放于 [cmd/](https://gitee.com/woood2/luca/tree/master/cmd) 的子目录中,跨入口公用的代码存放于 [internal/](https://gitee.com/woood2/luca/tree/master/internal) 下,例如:
- backend Controller层代码:[cmd/backend/internal/controller/](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/controller)
- Service层代码:[internal/service/](https://gitee.com/woood2/luca/tree/master/internal/service)
- Repository层代码:[internal/repository/](https://gitee.com/woood2/luca/tree/master/internal/repository)
同一种作业类型,可以创建多个入口。例如:项目中允许存在`backend`与`frontend`两个Restful服务。
示例1:添加`frontend`入口
1. 复制目录:`cp -a cmd/backend cmd/frontend`
2. 在 `cmd/frontend` 路径下批量替换:`backend=>frontend`、`Backend=>Frontend`
3. 修改配置:[internal/conf/attr.go](https://gitee.com/woood2/luca/tree/master/internal/conf/attr.go) 、[configs/application-example.yml](https://gitee.com/woood2/luca/tree/master/configs/application-example.yml)
示例2:删除`frontend`入口
1. 删除目录:`rm -rf cmd/frontend`
2. 修改配置:[internal/conf/attr.go](https://gitee.com/woood2/luca/tree/master/internal/conf/attr.go) 、[configs/application-example.yml](https://gitee.com/woood2/luca/tree/master/configs/application-example.yml)
### 运行
step1.安装Go环境以及所依赖的服务,详见 [deployments/README.md](https://gitee.com/woood2/luca/tree/master/deployments/README.md) 。
step2.执行init脚本,键入本机IP,生成 `configs/application.yml`。
```
cd scripts
./init.sh
```
step3.执行 `go run cmd/{xyz}/main.go`。
### 配置
文件路径
- 本地开发:`configs/application.yml`
- 远程部署:`程序运行目录/application.yml`
文件结构
- stub:用于设置本机host以及配置类型。
- detail:可供多个go程序实例复用的详细配置,根据stub设置决定其存放位置。
stub详解
| 一级 | 二级 | 说明 | 示例 |
| ---- | ---- | ---- | ---- |
| host | | 本机IP地址 | 192.168.1.100 |
| configType | | file:本地文件 consul:配置中心 | consul |
| dataKey | | consul kv键名 | config/luca/attr |
| consul | | | |
| | host | consul主机 | 192.168.1.100 |
| | port | consul端口 | 8500 |
本地文件示例
```
application.yml
# === stub part ===
host: {ip}
configType: file
dataKey:
consul:
host:
port:
# === detail part ===
project: luca
mysql:
user: root
pwd: '123456'
host: {ip}
port: 3306
db: luca
```
配置中心示例
```
application.yml
# === stub part ===
host: {ip}
configType: consul
dataKey: config/luca/attr
consul:
host: {ip}
port: 8500
访问consul后台,配置KV字典如下:
< Key/Values < config < luca
attr
Value
# === detail part ===
project: luca
mysql:
user: root
pwd: '123456'
host: {ip}
port: 3306
db: luca
```
detail详解
| 一级 | 二级 | 说明 | 示例 |
|------------|--------------|-------------------------|--------------------------------------------------------------------------------------------------------|
| project | | 项目名 | luca |
| env | | 环境:dev/demo/test/pre/pro | dev |
| consoleLog | | true:控制台日志
false:文件日志 | true |
| pprof | | | |
| | user | 用户名 | qjs |
| | pwd | 密码 | 731 |
| debug | | | |
| | on | 开关 | false |
| zipkin | | | |
| | reporterAddr | 上报地址(允许为空) | http://192.168.1.100:9411/api/v2/spans |
| mysql | | | |
| | user | 用户名 | root |
| | pwd | 密码 | 123456 |
| | host | 主机 | 192.168.1.100 |
| | port | 端口 | 3306 |
| | db | 数据库 | luca |
| | maxOpenConns | 最大连接数 | 30 |
| | maxIdleConns | 最大空闲连接数 | 10 |
| mongo | | | |
| | user | 用户名 | woood2 |
| | pwd | 密码 | 123456 |
| | host | 主机 | 192.168.1.100 |
| | port | 端口 | 27017 |
| | db | 数据库 | luca |
| | maxPoolSize | 最大连接数 | 30 |
| | minPoolSize | 最小连接数 | 10 |
| redis | | | |
| | addr | 地址 | 192.168.1.100:6379 |
| | pwd | 密码 | |
| | poolSize | 最大连接数 | 30 |
| | minIdleConns | 最小空闲连接数 | 10 |
| kafka | | | |
| | version | 版本 | 2.5.0 |
| | brokers | broker地址(允许多个) | 192.168.1.100:9092 |
| | enableSASL | 是否开启SASL | true |
| | user | 用户名 | qjs |
| | password | 密码 | 731 |
| | algorithm | 算法 | sha256 |
| backend | | | |
| | port | Restful端口 | 8080 |
| | register | 是否注册到consul | true |
| | pprofAddr | pprof地址 | :6060 |
| | observeAddr | 可观测地址 | :7070 |
| | allowOrigins | 允许来源(允许多个) | * |
| micro | | | |
| | port | 端口 | 8081 |
| | register | 是否注册到consul | true |
| | pprofAddr | pprof地址 | :6061 |
| | observeAddr | 可观测地址 | :7071 |
| consumer | | | |
| | pprofAddr | pprof地址 | :6062 |
| | observeAddr | 可观测地址 | :7072 |
| cron | | | |
| | pprofAddr | pprof地址 | :6063 |
| | observeAddr | 可观测地址 | :7073 |
| | jobs | 任务频率 | - name: "greet"
spec: "*/5 * * * * *"
- name: "hello"
spec: "@every 10s" |
| nav | | | |
| | addr | 监听地址 | :8888 |
| | hosts | 入口地址 | 详见 [deployments/nav/README.md](https://gitee.com/woood2/luca/tree/master/deployments/nav/README.md) |
| | links | 链接列表 | 详见 [deployments/nav/README.md](https://gitee.com/woood2/luca/tree/master/deployments/nav/README.md) |
### 错误处理
luca倡导在项目中借助多返回值传递error,而非滥用panic。
统一的错误字典:[internal/wrong/dict.go](https://gitee.com/woood2/luca/tree/master/internal/wrong/dict.go)
自定义error类型:[internal/wrong/errcode.go](https://gitee.com/woood2/luca/tree/master/internal/wrong/errcode.go)
```
package wrong
import "fmt"
type ErrorCode struct {
Code string
Message string
}
func New(code, message string) *ErrorCode {
return &ErrorCode{code, message}
}
func (err *ErrorCode) Error() string {
return fmt.Sprintf("ErrorCode error: code = %s msg = %s", err.Code, err.Message)
}
```
接口响应类型:[internal/wrong/resp.go](https://gitee.com/woood2/luca/tree/master/internal/wrong/resp.go)
```
package wrong
//4 restful & micro service
type Resp struct {
ErrCode string `json:"errCode"`
ErrMsg string `json:"errMsg"`
Data any `json:"data"`
TraceID string `json:"traceID"` //only 4 restful
Stack string `json:"stack"` //only 4 restful, non-pro env
}
```
一次`Restful请求`的错误处理
- 当程序走入错误分支或者发生内部错误,一个`error`对象被逐层传递到最上层的`controller`中。
- 持有这个`error`对象的`controller`前往`错误字典`查找对应的`错误代码`,并封装成`Resp`对象作为http返回值。
- 每个`错误代码`对应一条程序分支,通常由用户的错误操作引发,例如"用户名或密码错误",无需记录日志,`http code`为200。
- 找不到`错误代码`的`error`统一归为`wrong.ServerErr`并且记录一条error等级的日志,`http code`为500。
- 顺利走完程序主分支的成功请求,`Resp.ErrCode`与`Resp.ErrMsg`均为空值,`Resp.Data`携带返回值正文,`http code`为200。
一次`微服务调用`的错误处理
- 当程序走入错误分支或者发生内部错误,一个`error`对象被逐层传递到最上层的`endpoint`中。
- 持有这个`error`对象的`endpoint`前往`错误字典`查找对应的`错误代码`,并封装成`Resp`对象作为返回值。
- 每个`错误代码`对应一条程序分支,通常由client的非法调用引发,例如"非法的鉴权凭证",无需记录日志,无需对接`hystrix`。
- 找不到`错误代码`的`error`需要记录一条error等级的日志,并且对接`hystrix`。
- 顺利走完程序主分支的成功调用,`Resp.ErrCode`与`Resp.ErrMsg`均为空值,`Resp.Data`携带返回值正文。
Crash-free
- 尽管luca不主张使用`panic-recover`,但无法保证第三方库没有`panic`,必须在`goroutine`级别进行`recover`,保障整个进程的运行安全。
- 捕获`panic`后,任何作业类型均会记录一条error等级的日志。
- Restful请求中发生`panic`,`http code`为500。
- 微服务调用中发生`panic`,需要对接`hystrix`。
### Restful服务
luca基于 [gin](https://github.com/gin-gonic/gin) 提供Restful服务。
示例
- 认证:[cmd/backend/internal/middleware/auth.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/middleware/auth.go)
- 授权:[cmd/backend/internal/middleware/perm.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/middleware/perm.go)
- validator:[cmd/backend/internal/controller/app.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/controller/app.go)
- CRUD:[cmd/backend/internal/controller/app.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/controller/app.go)
基于 [gin-contrib/cors](https://github.com/gin-contrib/cors) 支持CORS。
允许多个来源:
```
backend:
allowOrigins:
- "http://google.com"
- "http://facebook.com"
```
允许任意来源:
```
backend:
allowOrigins:
- "*"
```
基于 [swaggo/swag](https://github.com/swaggo/swag/blob/master/README_zh-CN.md) 支持API文档。
示例
- 全局注释:[cmd/backend/main.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/main.go)
- API注释:[cmd/backend/internal/controller/app.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/controller/app.go)
- 更新命令:`cd cmd/backend && ./swag.sh`
### 微服务
luca 基于 [go-kit](https://github.com/go-kit/kit) 提供micro service。
详细选型
- 通信:[gRPC](https://doc.oschina.net/grpc)
- 注册/配置中心:[consul](https://developer.hashicorp.com/consul/docs/architecture)
- 熔断器:[hystrix](https://pkg.go.dev/github.com/afex/hystrix-go/hystrix)
- validator:[go-playground/validator](https://github.com/go-playground/validator)
API示例
- [cmd/micro/internal/grpc/check_perm.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/internal/grpc/check_perm.go)
- [cmd/micro/internal/grpc/check_token.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/internal/grpc/check_token.go)
SDK示例
- [cmd/micro/pkg/check_perm.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/pkg/check_perm.go)
- [cmd/micro/pkg/check_token.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/pkg/check_token.go)
本地测试
- [test/grpc_client/main.go](https://gitee.com/woood2/luca/tree/master/test/grpc_client/main.go)
### 定时任务
luca基于 [robfig-cron](https://github.com/robfig/cron) 提供定时任务。
基于redis实现`Secondary Nodes`模式的高可用,详见 [main.go](https://gitee.com/woood2/luca/tree/master/cmd/cron/main.go) 中的`campaign()`与`renew()`。
job示例
- [cmd/cron/internal/handler/greet.go](https://gitee.com/woood2/luca/tree/master/cmd/cron/internal/handler/greet.go)
- [cmd/cron/internal/handler/hello.go](https://gitee.com/woood2/luca/tree/master/cmd/cron/internal/handler/hello.go)
### 消息队列
luca 基于 [Shopify/sarama](https://github.com/Shopify/sarama) 支持 Kafka。
application.yml
```
kafka:
version: 2.5.0
brokers:
- {ip}:9092
enableSASL: true
user: qjs
password: '731'
algorithm: sha256
```
示例
- topic:[internal/mq/greet.go](https://gitee.com/woood2/luca/tree/master/internal/mq/greet.go)
- 生产:[internal/producer/sarama_producer_test.go:TestSendMessage](https://gitee.com/woood2/luca/tree/master/internal/producer/sarama_producer_test.go)
- 消费:[cmd/consumer/internal/handler/greet_one.go](https://gitee.com/woood2/luca/tree/master/cmd/consumer/internal/handler/greet_one.go)
### 分层
推荐方案

controller层包括:
- Restful服务中的 [Controller](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/controller)
- 微服务中的 [Endpoint](https://gitee.com/woood2/luca/tree/master/cmd/micro/internal/endpoint)
- 定时任务中的 [Handler](https://gitee.com/woood2/luca/tree/master/cmd/cron/internal/handler)
- 队列消费中的 [Handler](https://gitee.com/woood2/luca/tree/master/cmd/consumer/internal/handler)
[service](https://gitee.com/woood2/luca/tree/master/internal/service) 层涵盖:
- Service: CRUD场景常见的服务层
- Domain: [《领域驱动设计》](https://book.douban.com/subject/5344973/) 描绘的领域层
[repository](https://gitee.com/woood2/luca/tree/master/internal/repository) 层负责操作ORM层,luca选择 [GORM](https://gorm.io/zh_CN/docs/index.html) 作为ORM框架。
[sdk](https://gitee.com/woood2/luca/tree/master/internal/sdk) 或 [kafka producer](https://gitee.com/woood2/luca/tree/master/internal/producer/sarama_producer.go) 可视作远程service。
### 依赖注入
在luca中,依赖注入随处可见:
| 被依赖的对象 | 接收注入的对象 |
| ---- | ---- |
| logger | 任何需要记录日志的代码 |
| db(mysql、redis、mongo等) | repository |
| consul client | sdk |
| kafka producer | controller、service |
| sdk | controller、service |
| service | controller |
| repository | service |
在Spring的世界中,使用`@Autowired`即可自动装配。但是在luca中,我们需要在以下位置手动装配:
- [cmd/backend/internal/assembly/route.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/assembly/route.go)
- [cmd/micro/internal/grpc/set.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/internal/grpc/set.go)
- [cmd/cron/internal/handler/set.go](https://gitee.com/woood2/luca/tree/master/cmd/cron/internal/handler/set.go)
- [cmd/consumer/internal/handler/groups.go](https://gitee.com/woood2/luca/tree/master/cmd/consumer/internal/handler/groups.go)
### Mysql
luca选择 [GORM](https://gorm.io/zh_CN/docs/index.html) 作为ORM框架。
application.yml
```
mysql:
user: root
pwd: '123456'
host: {ip}
port: 3306
db: luca
maxOpenConns: 30
maxIdleConns: 10
```
示例
- CRUD:[internal/repository/app.go ](https://gitee.com/woood2/luca/tree/master/internal/repository/app.go)
- 事务:[AppServiceImpl.Twins](https://gitee.com/woood2/luca/tree/master/internal/service/app.go)
### MongoDB
luca 基于 [mongo-go-driver](https://github.com/mongodb/mongo-go-driver) 操作MongoDB。
application.yml
```
mongo:
user: woood2
pwd: '123456'
host: {ip}
port: 27017
db: luca
maxPoolSize: 30
minPoolSize: 10
```
示例
- [internal/repository/student.go](https://gitee.com/woood2/luca/tree/master/internal/repository/student.go)
### 缓存
luca提供了统一的 [Cache](https://gitee.com/woood2/luca/tree/master/internal/cache/cache.go) 接口以及3种默认实现:
- [LocalCache](https://gitee.com/woood2/luca/tree/master/internal/cache/local.go):基于本地内存的cache实现,性能水平100w/sec。
- [RedisCache](https://gitee.com/woood2/luca/tree/master/internal/cache/redis.go) :基于redis的cache实现,性能水平1w/sec。
- [NopCache](https://gitee.com/woood2/luca/tree/master/internal/cache/nop.go):基于「无」的cache实现。
其中,[RedisCache](https://gitee.com/woood2/luca/tree/master/internal/cache/redis.go) 基于 [go-redis](https://github.com/go-redis/redis) 操作Redis,对应配置:
```
redis:
addr: {ip}:6379
pwd: ''
poolSize: 30
minIdleConns: 10
```
默认采用json序列化,允许修改 [serialization.go](https://gitee.com/woood2/luca/tree/master/internal/cache/serialization.go) 替换成其它序列化算法。
示例
- Local: [local_test.go](https://gitee.com/woood2/luca/tree/master/internal/cache/local_test.go)
- Redis: [redis_test.go](https://gitee.com/woood2/luca/tree/master/internal/cache/redis_test.go)
- 防雪崩:[AppServiceImpl.GetByKeyFromCacheSafely](https://gitee.com/woood2/luca/tree/master/internal/service/app.go)
### logger
日志维度
| 日志维度 | 说明 | 日志库 | 输出 | 接入 [zipkin](https://zipkin.io/) | 接入 [EFK](https://blog.csdn.net/easylife206/article/details/112057417) |
| ---- | ---- | ---- | ---- | ---- | ---- |
| 服务日志 | 服务运行周期中的启动、关闭和状态日志 | 标准库 [log](https://pkg.go.dev/log) | stdout/stderr | 否 | 否 |
| 请求日志 | 请求/作业周期内产生的日志 | [uber-go/zap](https://github.com/uber-go/zap) | stdout/stderr或者./zap.log文件 | 是 | 是 |
application.yml(zap配置)
| 名称 | 说明 |
| ---- | ---- |
| env | pro: 日志等级Info
其它: 日志等级Debug |
| consoleLog | true: 控制台日志
false: 文件日志(./zap.log) |
内置日志点(zap logger)
| 围绕 | 类型 | 说明 | 等级 |
| ---- | ---- | ---- | ---- |
| 请求/作业 | | | |
| | access日志 | 覆盖所有作业类型 | info |
| | error日志 | 覆盖所有作业类型 | error |
| | oplog日志 | 用于Restful服务 | info |
| GORM | | | |
| | sql日志 | | debug |
| | slow日志 | | warn |
| | error日志 | | error |
| SDK | | | |
| | call日志 | | debug |
| | error日志 | | error |
### 链路追踪
luca 选择 [zipkin](https://zipkin.io/) 作为链路追踪的实现引擎。
跟踪范围
- Restful请求
- 微服务调用
- 定时任务作业
- 队列消费作业
- 其它,如单元测试
从 gin.Context 提取 TraceID:
```
func (ctr *AnyController) Demo(c *gin.Context) {
traceID := trace.GinID(c)
...
}
```
将 gin.Context 转换为 context.Context
```
func (ctr *AnyController) Demo(c *gin.Context) {
ctx:=trace.Ctx(c)
...
}
```
从 context.Context 提取 TraceID:
```
func demo(ctx context.Context) {
traceID := trace.ID(ctx)
...
}
```
向 GORM logger 传递 TraceID:
```
func (repo *AnyRepoImpl) Create(ctx context.Context, entity *Any) (int, error) {
result := repo.DB.WithContext(ctx).Create(entity)
...
}
```
从 Restful 响应读取 TraceID:
```
package wrong
type Resp struct {
ErrCode string `json:"errCode"`
ErrMsg string `json:"errMsg"`
Data any `json:"data"`
TraceID string `json:"traceID"`
Stack string `json:"stack"`
}
```
application.yml
| 一级 | 二级 | 说明 | 示例 |
| ---- | ---- | ---- | ---- |
| zipkin | | | |
| | reporterAddr | 上报地址(允许为空) | http://192.168.0.100:9411/api/v2/spans |
zipkin server
- 安装:[deployments/README.md](https://gitee.com/woood2/luca/tree/master/deployments/README.md)
- 访问:详见 [deployments/nav/README.md](https://gitee.com/woood2/luca/tree/master/deployments/nav/README.md)
- 为性能考虑,生产环境建议关闭zipkin server,只需要将Zipkin.ReporterAddr设置为空。
### 日志收集
luca 选择 [EFK](https://blog.csdn.net/easylife206/article/details/112057417) 日志收集方案:
- 通过 [fluentd](https://docs.fluentd.org) 从 ./zap.log 文件中读取日志。
- 将收集来的日志数据存入 [elastic search](https://www.elastic.co/cn/what-is/elasticsearch) 。
- 通过 [Kibana](https://www.elastic.co/cn/kibana/) 界面查询日志。
EFK 安装、使用
- 详见 [deployments/EFK.md](https://gitee.com/woood2/luca/tree/master/deployments/EFK.md)
### pprof
支持 [pprof](https://pkg.go.dev/net/http/pprof) 的Go进程:
- Restful服务
- 微服务
- 定时任务
- 队列消费
application.yml
```
pprof:
user: qjs
pwd: '731'
backend:
pprofAddr: ":6060"
micro:
pprofAddr: ":6061"
consumer:
pprofAddr: ":6062"
cron:
pprofAddr: ":6063"
```
访问
- 详见 [deployments/nav/README.md](https://gitee.com/woood2/luca/tree/master/deployments/nav/README.md)
### metrics
luca 为3种作业类型接入 [prometheus](https://prometheus.io/) 指标统计:
- Restful请求
- 微服务调用
- 队列消费作业
application.yml
```
backend:
observeAddr: ":7070"
micro:
observeAddr: ":7071"
consumer:
observeAddr: ":7072"
```
安装 prometheus
- 详见 [deployments/README.md](https://gitee.com/woood2/luca/tree/master/deployments/README.md)
访问 prometheus
- 详见 [deployments/nav/README.md](https://gitee.com/woood2/luca/tree/master/deployments/nav/README.md)
### 多环境
推荐方案
| 环境 | env | 部署位置 | 部署套数 | 用途 |git分支 | zap等级 | swagger |
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
| 本机 | dev | 本机 | 1/每人 | 开发 | 个人、feature、fixbug | Debug | 开启 |
| dev | dev | 远程 | 1 | 联调 | dev | Debug | 开启 |
| demo | demo | 远程 | 1 | 对客演示 | demo | Debug | 开启 |
| test | test | 远程 | \>=1 | 测试 | test | Debug | 开启 |
| pre | pre | 远程 | 1 | 发版演练 | pre | Debug | 开启 |
| pro | pro | 远程 | \>=1 | 生产 | master | Info | 关闭 |
本机 & dev
- 允许本机环境与dev环境共用同一套资源,如数据库、消息队列等。
- 允许本机程序单向依赖dev环境的微服务,只需在本机配置dev环境的consul地址,并且将Backend.Register、Micro.Register设置为false。
demo
- 假如demo环境的使用频率较低,建议按需构建。
- 考虑到demo环境的不确定性,暂不纳入 `git 分支策略`。
git 分支策略

git 分支命名
| 分支 | 命名规则 | 示例 |
| ---- | ---- | ---- |
| 主分支 | master | - |
| 开发 | dev | - |
| 演示 | demo | - |
| 测试 | test | - |
| 预生产 | pre | - |
| feature | {name}-feature | first-feature、second-feature |
| fixbug | {name}-fixbug | stackoverflow-fixbug |
| 个人 | 姓名全拼、缩写 | qiujiashu、qjs |
### 优雅关闭
支持优雅关闭的Go进程
- Restful服务
- 微服务
- 定时任务
- 队列消费
工作原理
1. 接收来自kill命令的信号量。
2. 停止接收新的作业。
3. 等待正在进行中的作业完成或者超时(默认:5秒)。
4. 关闭进程。
### 灰度发布
luca支持微服务及Restful服务的灰度发布,以实现程序的不停服更新。
前提
- 不论是Restful服务还是微服务,运行的实例数量必须是两个及以上,单机模式不支持灰度发布。
- Restful服务需要前置一个nginx反向代理,并且借助consul-template监视实例列表的变化。详见:[Load Balancing with NGINX and Consul Template](https://developer.hashicorp.com/consul/tutorials/load-balancing/load-balancing-nginx)
工作原理
- 发布程序的新版本时,分批重启集群中的实例。
- 实例重启前通知consul注销自己,将流量导向其它运行中的实例。
- 等待实例重启完成,再次注册到consul上迎回流量。
- 发布过程中,始终有实例运行,提供连续服务。
### 单元测试
luca鼓励开发者采用主流的`table driven`模式进行单元测试。
单元测试的优先目标是计算逻辑,而不是IO。对于一般的CRUD,单元测试意义不大,API测试是更适合的选择。
luca支持在CI/CD中跳过指定的单元测试:
```
CLI
CI=true go test -v -cover ./...
internal/util/test.go
package util
import (
"os"
"testing"
)
func CI() bool {
return os.Getenv("CI") != ""
}
func SkipCI(t *testing.T) {
if CI() {
t.Skip("Skipping testing in CI environment")
}
}
xxx_test.go
func TestMain(m *testing.M) {
if !util.CI() {
attr := conf.Load("application.yml", "configs/application.yml")
..
}
m.Run()
}
func TestXXX(t *testing.T) {
util.SkipCI(t)
..
}