Repository: zeromicro/go-zero
Pull request #1581 (2022-02-26 11:18:13)

fix: HitQuota should be returned instead of Allowed when limit is equ…
…al to 1.


Patch:
diff --git a/core/limit/periodlimit.go b/core/limit/periodlimit.go
index edb737e8..73fb9d00 100644
--- a/core/limit/periodlimit.go
+++ b/core/limit/periodlimit.go
@@ -14,8 +14,8 @@ local window = tonumber(ARGV[2])
 local current = redis.call("INCRBY", KEYS[1], 1)
 if current == 1 then
     redis.call("expire", KEYS[1], window)
-    return 1
-elseif current < limit then
+end
+if current < limit then
     return 1
 elseif current == limit then
     return 2
diff --git a/core/logx/durationlogger.go b/core/logx/durationlogger.go
index ab26a0a6..7108a939 100644
--- a/core/logx/durationlogger.go
+++ b/core/logx/durationlogger.go
@@ -3,6 +3,7 @@ package logx
 import (
 	"fmt"
 	"io"
+	"sync/atomic"
 	"time"
 
 	"github.com/zeromicro/go-zero/core/timex"
@@ -79,7 +80,7 @@ func (l *durationLogger) WithDuration(duration time.Duration) Logger {
 }
 
 func (l *durationLogger) write(writer io.Writer, level string, val interface{}) {
-	switch encoding {
+	switch atomic.LoadUint32(&encoding) {
 	case plainEncodingType:
 		writePlainAny(writer, level, val, l.Duration)
 	default:
diff --git a/core/logx/logs.go b/core/logx/logs.go
index 34bb1112..c0a3315a 100644
--- a/core/logx/logs.go
+++ b/core/logx/logs.go
@@ -75,7 +75,7 @@ var (
 	timeFormat   = "2006-01-02T15:04:05.000Z07:00"
 	writeConsole bool
 	logLevel     uint32
-	encoding     = jsonEncodingType
+	encoding     uint32 = jsonEncodingType
 	// use uint32 for atomic operations
 	disableStat uint32
 	infoLog     io.WriteCloser
@@ -137,9 +137,9 @@ func SetUp(c LogConf) error {
 	}
 	switch c.Encoding {
 	case plainEncoding:
-		encoding = plainEncodingType
+		atomic.StoreUint32(&encoding, plainEncodingType)
 	default:
-		encoding = jsonEncodingType
+		atomic.StoreUint32(&encoding, jsonEncodingType)
 	}
 
 	switch c.Mode {
@@ -424,7 +424,7 @@ func infoTextSync(msg string) {
 }
 
 func outputAny(writer io.Writer, level string, val interface{}) {
-	switch encoding {
+	switch atomic.LoadUint32(&encoding) {
 	case plainEncodingType:
 		writePlainAny(writer, level, val)
 	default:
@@ -438,7 +438,7 @@ func outputAny(writer io.Writer, level string, val interface{}) {
 }
 
 func outputText(writer io.Writer, level, msg string) {
-	switch encoding {
+	switch atomic.LoadUint32(&encoding) {
 	case plainEncodingType:
 		writePlainText(writer, level, msg)
 	default:
diff --git a/core/logx/tracelogger.go b/core/logx/tracelogger.go
index e2702d51..647f3dff 100644
--- a/core/logx/tracelogger.go
+++ b/core/logx/tracelogger.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 	"io"
+	"sync/atomic"
 	"time"
 
 	"github.com/zeromicro/go-zero/core/timex"
@@ -80,7 +81,7 @@ func (l *traceLogger) write(writer io.Writer, level string, val interface{}) {
 	traceID := traceIdFromContext(l.ctx)
 	spanID := spanIdFromContext(l.ctx)
 
-	switch encoding {
+	switch atomic.LoadUint32(&encoding) {
 	case plainEncodingType:
 		writePlainAny(writer, level, val, l.Duration, traceID, spanID)
 	default:
diff --git a/core/stores/mongoc/cachedcollection.go b/core/stores/mongoc/cachedcollection.go
index 49fdd203..3b4742fb 100644
--- a/core/stores/mongoc/cachedcollection.go
+++ b/core/stores/mongoc/cachedcollection.go
@@ -12,8 +12,8 @@ var (
 	ErrNotFound = mgo.ErrNotFound
 
 	// can't use one SingleFlight per conn, because multiple conns may share the same cache key.
-	sharedCalls = syncx.NewSingleFlight()
-	stats       = cache.NewStat("mongoc")
+	singleFlight = syncx.NewSingleFlight()
+	stats        = cache.NewStat("mongoc")
 )
 
 type (
diff --git a/core/stores/mongoc/cachedmodel.go b/core/stores/mongoc/cachedmodel.go
index c366cc3c..919afcea 100644
--- a/core/stores/mongoc/cachedmodel.go
+++ b/core/stores/mongoc/cachedmodel.go
@@ -38,7 +38,7 @@ func MustNewModel(url, collection string, c cache.CacheConf, opts ...cache.Optio
 
 // NewModel returns a Model with a cache cluster.
 func NewModel(url, collection string, conf cache.CacheConf, opts ...cache.Option) (*Model, error) {
-	c := cache.New(conf, sharedCalls, stats, mgo.ErrNotFound, opts...)
+	c := cache.New(conf, singleFlight, stats, mgo.ErrNotFound, opts...)
 	return NewModelWithCache(url, collection, c)
 }
 
@@ -51,7 +51,7 @@ func NewModelWithCache(url, collection string, c cache.Cache) (*Model, error) {
 
 // NewNodeModel returns a Model with a cache node.
 func NewNodeModel(url, collection string, rds *redis.Redis, opts ...cache.Option) (*Model, error) {
-	c := cache.NewNode(rds, sharedCalls, stats, mgo.ErrNotFound, opts...)
+	c := cache.NewNode(rds, singleFlight, stats, mgo.ErrNotFound, opts...)
 	return NewModelWithCache(url, collection, c)
 }
 
diff --git a/go.mod b/go.mod
index 98c14a20..dff028d2 100644
--- a/go.mod
+++ b/go.mod
@@ -17,8 +17,8 @@ require (
 	github.com/prometheus/client_golang v1.11.0
 	github.com/spaolacci/murmur3 v1.1.0
 	github.com/stretchr/testify v1.7.0
-	go.etcd.io/etcd/api/v3 v3.5.1
-	go.etcd.io/etcd/client/v3 v3.5.1
+	go.etcd.io/etcd/api/v3 v3.5.2
+	go.etcd.io/etcd/client/v3 v3.5.2
 	go.opentelemetry.io/otel v1.3.0
 	go.opentelemetry.io/otel/exporters/jaeger v1.3.0
 	go.opentelemetry.io/otel/exporters/zipkin v1.3.0
@@ -44,8 +44,11 @@ require (
 	github.com/go-redis/redis/v8 v8.11.4
 	github.com/mattn/go-runewidth v0.0.13 // indirect
 	github.com/openzipkin/zipkin-go v0.4.0 // indirect
-	golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
-	golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
-	google.golang.org/genproto v0.0.0-20220211171837-173942840c17 // indirect
+	go.uber.org/atomic v1.9.0 // indirect
+	go.uber.org/multierr v1.8.0 // indirect
+	go.uber.org/zap v1.21.0 // indirect
+	golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
+	golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect
+	google.golang.org/genproto v0.0.0-20220228195345-15d65a4533f7 // indirect
 	k8s.io/klog/v2 v2.40.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 9391f6e7..4059a4a2 100644
--- a/go.sum
+++ b/go.sum
@@ -52,6 +52,7 @@ github.com/alicebob/miniredis/v2 v2.17.0 h1:EwLdrIS50uczw71Jc7iVSxZluTKj5nfSP8n7
 github.com/alicebob/miniredis/v2 v2.17.0/go.mod h1:gquAfGbzn92jvtrSC69+6zZnwSODVXVpYDRaGhWaL6I=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -378,10 +379,16 @@ github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5u
 github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
 go.etcd.io/etcd/api/v3 v3.5.1 h1:v28cktvBq+7vGyJXF8G+rWJmj+1XUmMtqcLnH8hDocM=
 go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
+go.etcd.io/etcd/api/v3 v3.5.2 h1:tXok5yLlKyuQ/SXSjtqHc4uzNaMqZi2XsoSPr/LlJXI=
+go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
 go.etcd.io/etcd/client/pkg/v3 v3.5.1 h1:XIQcHCFSG53bJETYeRJtIxdLv2EWRGxcfzR8lSnTH4E=
 go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/pkg/v3 v3.5.2 h1:4hzqQ6hIb3blLyQ8usCU4h3NghkqcsohEQ3o3VetYxE=
+go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
 go.etcd.io/etcd/client/v3 v3.5.1 h1:oImGuV5LGKjCqXdjkMHCyWa5OO1gYKCnC/1sgdfj1Uk=
 go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q=
+go.etcd.io/etcd/client/v3 v3.5.2 h1:WdnejrUtQC4nCxK0/dLTMqKOB+U5TP/2Ya0BJL+1otA=
+go.etcd.io/etcd/client/v3 v3.5.2/go.mod h1:kOOaWFFgHygyT0WlSmL8TJiXmMysO/nNUlEsSsN6W4o=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -399,14 +406,21 @@ go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKu
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
 go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
+go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
 go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
+go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
 go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
+go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -485,6 +499,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
 golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -548,6 +564,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
 golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
+golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -648,6 +666,8 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY
 google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
 google.golang.org/genproto v0.0.0-20220211171837-173942840c17 h1:2X+CNIheCutWRyKRte8szGxrE5ggtV4U+NKAbh/oLhg=
 google.golang.org/genproto v0.0.0-20220211171837-173942840c17/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
+google.golang.org/genproto v0.0.0-20220228195345-15d65a4533f7 h1:ntPPoHzFW6Xp09ueznmahONZufyoSakK/piXnr2BU3I=
+google.golang.org/genproto v0.0.0-20220228195345-15d65a4533f7/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
diff --git a/readme-cn.md b/readme-cn.md
index 716059d3..e8bae5ca 100644
--- a/readme-cn.md
+++ b/readme-cn.md
@@ -13,7 +13,15 @@
 
 > ***缩短从需求到上线的距离***
 
-**注意：为了满足开源基金会要求，go-zero 从好未来（tal-tech）组织下迁移至中立的 GitHub 组织（zeromicro）。**
+**为了满足开源基金会要求，go-zero 从好未来（tal-tech）组织下迁移至中立的 GitHub 组织（zeromicro）。**
+
+> ***注意：***
+>
+> 从 v1.3.0 之前版本升级请执行以下命令：
+> 
+> `GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest`
+> 
+> `goctl migrate —verbose —version v1.3.1`
 
 ## 0. go-zero 介绍
 
@@ -244,6 +252,8 @@ go-zero 已被许多公司用于生产部署，接入场景如在线教育、电
 >56. 时代脉搏网络科技（云浮市）有限公司
 >57. 店有帮
 >58. 七牛云
+>59. 费芮网络
+>60. 51CTO
 
 如果贵公司也已使用 go-zero，欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记，仅仅为了推广，不做其它用途。
 
diff --git a/readme.md b/readme.md
index 0c7263b8..0b9a8bff 100644
--- a/readme.md
+++ b/readme.md
@@ -10,9 +10,18 @@ English | [简体中文](readme-cn.md)
 [![Release](https://img.shields.io/github/v/release/zeromicro/go-zero.svg?style=flat-square)](https://github.com/zeromicro/go-zero)
 [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
 [![Discord](https://img.shields.io/discord/794530774463414292?label=chat&logo=discord)](https://discord.gg/4JQvC5A4Fe)
+<a href="https://www.producthunt.com/posts/go-zero?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-go&#0045;zero" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=334030&theme=light" alt="go&#0045;zero - A&#0032;web&#0032;&#0038;&#0032;rpc&#0032;framework&#0032;written&#0032;in&#0032;Go&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
 
 **Note: To meet the requirements of Open Source Foundation, we moved go-zero from tal-tech to zeromicro (a neutral GitHub organization).**
 
+> ***Important!***
+> 
+> To upgrade from versions eariler than v1.3.0, run the following commands.
+> 
+> `go install github.com/zeromicro/go-zero/tools/goctl@latest`
+> 
+> `goctl migrate —verbose —version v1.3.1`
+
 ## 0. what is go-zero
 
 go-zero (listed in CNCF Landscape: [https://landscape.cncf.io/?selected=go-zero](https://landscape.cncf.io/?selected=go-zero)) is a web and rpc framework with lots of builtin engineering practices. It’s born to ensure the stability of the busy services with resilience design and has been serving sites with tens of millions of users for years.
diff --git a/tools/goctl/.gitignore b/tools/goctl/.gitignore
new file mode 100644
index 00000000..722d5e71
--- /dev/null
+++ b/tools/goctl/.gitignore
@@ -0,0 +1,1 @@
+.vscode
diff --git a/tools/goctl/api/dartgen/format.go b/tools/goctl/api/dartgen/format.go
new file mode 100644
index 00000000..029e3bec
--- /dev/null
+++ b/tools/goctl/api/dartgen/format.go
@@ -0,0 +1,40 @@
+package dartgen
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+)
+
+const dartExec = "dart"
+
+func formatDir(dir string) error {
+	ok, err := dirctoryExists(dir)
+	if err != nil {
+		return err
+	}
+	if !ok {
+		return fmt.Errorf("format failed, directory %q does not exist", dir)
+	}
+
+	_, err = exec.LookPath(dartExec)
+	if err != nil {
+		return err
+	}
+	cmd := exec.Command(dartExec, "format", dir)
+	cmd.Env = os.Environ()
+	cmd.Stderr = os.Stderr
+
+	return cmd.Run()
+}
+
+func dirctoryExists(dir string) (bool, error) {
+	_, err := os.Stat(dir)
+	if err == nil {
+		return true, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil
+	}
+	return false, err
+}
diff --git a/tools/goctl/api/dartgen/gen.go b/tools/goctl/api/dartgen/gen.go
index 3bb08a99..c7078bf2 100644
--- a/tools/goctl/api/dartgen/gen.go
+++ b/tools/goctl/api/dartgen/gen.go
@@ -2,6 +2,7 @@ package dartgen
 
 import (
 	"errors"
+	"fmt"
 	"strings"
 
 	"github.com/urfave/cli"
@@ -13,12 +14,18 @@ import (
 func DartCommand(c *cli.Context) error {
 	apiFile := c.String("api")
 	dir := c.String("dir")
+	isLegacy := c.Bool("legacy")
+	hostname := c.String("hostname")
 	if len(apiFile) == 0 {
 		return errors.New("missing -api")
 	}
 	if len(dir) == 0 {
 		return errors.New("missing -dir")
 	}
+	if len(hostname) == 0 {
+		fmt.Println("you could use '-hostname' flag to specify your server hostname")
+		hostname = "go-zero.dev"
+	}
 
 	api, err := parser.Parse(apiFile)
 	if err != nil {
@@ -30,8 +37,11 @@ func DartCommand(c *cli.Context) error {
 		dir = dir + "/"
 	}
 	api.Info.Title = strings.Replace(apiFile, ".api", "", -1)
-	logx.Must(genData(dir+"data/", api))
-	logx.Must(genApi(dir+"api/", api))
-	logx.Must(genVars(dir + "vars/"))
+	logx.Must(genData(dir+"data/", api, isLegacy))
+	logx.Must(genApi(dir+"api/", api, isLegacy))
+	logx.Must(genVars(dir+"vars/", isLegacy, hostname))
+	if err := formatDir(dir); err != nil {
+		logx.Errorf("failed to format, %v", err)
+	}
 	return nil
 }
diff --git a/tools/goctl/api/dartgen/genapi.go b/tools/goctl/api/dartgen/genapi.go
index 380b858a..7f735a81 100644
--- a/tools/goctl/api/dartgen/genapi.go
+++ b/tools/goctl/api/dartgen/genapi.go
@@ -2,13 +2,14 @@ package dartgen
 
 import (
 	"os"
+	"strings"
 	"text/template"
 
 	"github.com/zeromicro/go-zero/tools/goctl/api/spec"
 )
 
 const apiTemplate = `import 'api.dart';
-import '../data/{{with .Info}}{{.Title}}{{end}}.dart';
+import '../data/{{with .Info}}{{getBaseName .Title}}{{end}}.dart';
 {{with .Service}}
 /// {{.Name}}
 {{range .Routes}}
@@ -22,24 +23,45 @@ Future {{pathToFuncName .Path}}( {{if ne .Method "get"}}{{with .RequestType}}{{.
     Function eventually}) async {
   await api{{if eq .Method "get"}}Get{{else}}Post{{end}}('{{.Path}}',{{if ne .Method "get"}}request,{{end}}
   	 ok: (data) {
-    if (ok != null) ok({{with .ResponseType}}{{.Name}}{{end}}.fromJson(data));
+    if (ok != null) ok({{with .ResponseType}}{{.Name}}.fromJson(data){{end}});
   }, fail: fail, eventually: eventually);
 }
 {{end}}
 {{end}}`
 
-func genApi(dir string, api *spec.ApiSpec) error {
+const apiTemplateV2 = `import 'api.dart';
+import '../data/{{with .Info}}{{getBaseName .Title}}{{end}}.dart';
+{{with .Service}}
+/// {{.Name}}
+{{range .Routes}}
+/// --{{.Path}}--
+///
+/// request: {{with .RequestType}}{{.Name}}{{end}}
+/// response: {{with .ResponseType}}{{.Name}}{{end}}
+Future {{pathToFuncName .Path}}( {{if ne .Method "get"}}{{with .RequestType}}{{.Name}} request,{{end}}{{end}}
+    {Function({{with .ResponseType}}{{.Name}}{{end}})? ok,
+    Function(String)? fail,
+    Function? eventually}) async {
+  await api{{if eq .Method "get"}}Get{{else}}Post{{end}}('{{.Path}}',{{if ne .Method "get"}}request,{{end}}
+  	 ok: (data) {
+    if (ok != null) ok({{with .ResponseType}}{{.Name}}.fromJson(data){{end}});
+  }, fail: fail, eventually: eventually);
+}
+{{end}}
+{{end}}`
+
+func genApi(dir string, api *spec.ApiSpec, isLegacy bool) error {
 	err := os.MkdirAll(dir, 0o755)
 	if err != nil {
 		return err
 	}
 
-	err = genApiFile(dir)
+	err = genApiFile(dir, isLegacy)
 	if err != nil {
 		return err
 	}
 
-	file, err := os.OpenFile(dir+api.Service.Name+".dart", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
+	file, err := os.OpenFile(dir+strings.ToLower(api.Service.Name+".dart"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
 	if err != nil {
 		return err
 	}
@@ -47,7 +69,11 @@ func genApi(dir string, api *spec.ApiSpec) error {
 	defer file.Close()
 	t := template.New("apiTemplate")
 	t = t.Funcs(funcMap)
-	t, err = t.Parse(apiTemplate)
+	tpl := apiTemplateV2
+	if isLegacy {
+		tpl = apiTemplate
+	}
+	t, err = t.Parse(tpl)
 	if err != nil {
 		return err
 	}
@@ -55,7 +81,7 @@ func genApi(dir string, api *spec.ApiSpec) error {
 	return t.Execute(file, api)
 }
 
-func genApiFile(dir string) error {
+func genApiFile(dir string, isLegacy bool) error {
 	path := dir + "api.dart"
 	if fileExists(path) {
 		return nil
@@ -66,6 +92,10 @@ func genApiFile(dir string) error {
 	}
 
 	defer apiFile.Close()
-	_, err = apiFile.WriteString(apiFileContent)
+	tpl := apiFileContentV2
+	if isLegacy {
+		tpl = apiFileContent
+	}
+	_, err = apiFile.WriteString(tpl)
 	return err
 }
diff --git a/tools/goctl/api/dartgen/gendata.go b/tools/goctl/api/dartgen/gendata.go
index 6b33e610..49c5f0a6 100644
--- a/tools/goctl/api/dartgen/gendata.go
+++ b/tools/goctl/api/dartgen/gendata.go
@@ -2,6 +2,7 @@ package dartgen
 
 import (
 	"os"
+	"strings"
 	"text/template"
 
 	"github.com/zeromicro/go-zero/tools/goctl/api/spec"
@@ -19,30 +20,52 @@ class {{.Name}}{
 	});
 	factory {{.Name}}.fromJson(Map<String,dynamic> m) {
 		return {{.Name}}({{range .Members}}
-			{{lowCamelCase .Name}}: {{if isDirectType .Type.Name}}m['{{tagGet .Tag "json"}}']{{else if isClassListType .Type.Name}}(m['{{tagGet .Tag "json"}}'] as List<dynamic>).map((i) => {{getCoreType .Type.Name}}.fromJson(i)){{else}}{{.Type.Name}}.fromJson(m['{{tagGet .Tag "json"}}']){{end}},{{end}}
+			{{lowCamelCase .Name}}: {{if isDirectType .Type.Name}}m['{{getPropertyFromMember .}}']{{else if isClassListType .Type.Name}}(m['{{getPropertyFromMember .}}'] as List<dynamic>).map((i) => {{getCoreType .Type.Name}}.fromJson(i)){{else}}{{.Type.Name}}.fromJson(m['{{getPropertyFromMember .}}']){{end}},{{end}}
 		);
 	}
 	Map<String,dynamic> toJson() {
 		return { {{range .Members}}
-			'{{tagGet .Tag "json"}}': {{if isDirectType .Type.Name}}{{lowCamelCase .Name}}{{else if isClassListType .Type.Name}}{{lowCamelCase .Name}}.map((i) => i.toJson()){{else}}{{lowCamelCase .Name}}.toJson(){{end}},{{end}}
+			'{{getPropertyFromMember .}}': {{if isDirectType .Type.Name}}{{lowCamelCase .Name}}{{else if isClassListType .Type.Name}}{{lowCamelCase .Name}}.map((i) => i.toJson()){{else}}{{lowCamelCase .Name}}.toJson(){{end}},{{end}}
 		};
 	}
 }
 {{end}}
 `
 
-func genData(dir string, api *spec.ApiSpec) error {
+const dataTemplateV2 = `// --{{with .Info}}{{.Title}}{{end}}--
+{{ range .Types}}
+class {{.Name}} {
+	{{range .Members}}
+	{{if .Comment}}{{.Comment}}{{end}}
+	final {{.Type.Name}} {{lowCamelCase .Name}};
+  {{end}}{{.Name}}({{if .Members}}{
+	{{range .Members}}  required this.{{lowCamelCase .Name}},
+	{{end}}}{{end}});
+	factory {{.Name}}.fromJson(Map<String,dynamic> m) {
+		return {{.Name}}({{range .Members}}
+			{{lowCamelCase .Name}}: {{if isDirectType .Type.Name}}m['{{getPropertyFromMember .}}']{{else if isClassListType .Type.Name}}(m['{{getPropertyFromMember .}}'] as List<dynamic>).map((i) => {{getCoreType .Type.Name}}.fromJson(i)){{else}}{{.Type.Name}}.fromJson(m['{{getPropertyFromMember .}}']){{end}},{{end}}
+		);
+	}
+	Map<String,dynamic> toJson() {
+		return { {{range .Members}}
+			'{{getPropertyFromMember .}}': {{if isDirectType .Type.Name}}{{lowCamelCase .Name}}{{else if isClassListType .Type.Name}}{{lowCamelCase .Name}}.map((i) => i.toJson()){{else}}{{lowCamelCase .Name}}.toJson(){{end}},{{end}}
+		};
+	}
+}
+{{end}}`
+
+func genData(dir string, api *spec.ApiSpec, isLegacy bool) error {
 	err := os.MkdirAll(dir, 0o755)
 	if err != nil {
 		return err
 	}
 
-	err = genTokens(dir)
+	err = genTokens(dir, isLegacy)
 	if err != nil {
 		return err
 	}
 
-	file, err := os.OpenFile(dir+api.Service.Name+".dart", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
+	file, err := os.OpenFile(dir+strings.ToLower(api.Service.Name+".dart"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
 	if err != nil {
 		return err
 	}
@@ -50,7 +73,11 @@ func genData(dir string, api *spec.ApiSpec) error {
 
 	t := template.New("dataTemplate")
 	t = t.Funcs(funcMap)
-	t, err = t.Parse(dataTemplate)
+	tpl := dataTemplateV2
+	if isLegacy {
+		tpl = dataTemplate
+	}
+	t, err = t.Parse(tpl)
 	if err != nil {
 		return err
 	}
@@ -63,7 +90,7 @@ func genData(dir string, api *spec.ApiSpec) error {
 	return t.Execute(file, api)
 }
 
-func genTokens(dir string) error {
+func genTokens(dir string, isLeagcy bool) error {
 	path := dir + "tokens.dart"
 	if fileExists(path) {
 		return nil
@@ -75,7 +102,11 @@ func genTokens(dir string) error {
 	}
 
 	defer tokensFile.Close()
-	_, err = tokensFile.WriteString(tokensFileContent)
+	tpl := tokensFileContentV2
+	if isLeagcy {
+		tpl = tokensFileContent
+	}
+	_, err = tokensFile.WriteString(tpl)
 	return err
 }
 
diff --git a/tools/goctl/api/dartgen/genvars.go b/tools/goctl/api/dartgen/genvars.go
index c6b90a56..51a9fa13 100644
--- a/tools/goctl/api/dartgen/genvars.go
+++ b/tools/goctl/api/dartgen/genvars.go
@@ -1,11 +1,13 @@
 package dartgen
 
 import (
+	"fmt"
 	"io/ioutil"
 	"os"
 )
 
-const varTemplate = `import 'dart:convert';
+const (
+	varTemplate = `import 'dart:convert';
 import 'package:shared_preferences/shared_preferences.dart';
 import '../data/tokens.dart';
 
@@ -40,21 +42,59 @@ Future<Tokens> getTokens() async {
 }
 `
 
-func genVars(dir string) error {
+	varTemplateV2 = `import 'dart:convert';
+import 'package:shared_preferences/shared_preferences.dart';
+import '../data/tokens.dart';
+
+const String _tokenKey = 'tokens';
+
+/// Saves tokens
+Future<bool> setTokens(Tokens tokens) async {
+  var sp = await SharedPreferences.getInstance();
+  return await sp.setString(_tokenKey, jsonEncode(tokens.toJson()));
+}
+
+/// remove tokens
+Future<bool> removeTokens() async {
+  var sp = await SharedPreferences.getInstance();
+  return sp.remove(_tokenKey);
+}
+
+/// Reads tokens
+Future<Tokens?> getTokens() async {
+  try {
+    var sp = await SharedPreferences.getInstance();
+    var str = sp.getString('tokens');
+    if (str.isEmpty) {
+      return null;
+    }
+    return Tokens.fromJson(jsonDecode(str));
+  } catch (e) {
+    print(e);
+    return null;
+  }
+}`
+)
+
+func genVars(dir string, isLegacy bool, hostname string) error {
 	err := os.MkdirAll(dir, 0o755)
 	if err != nil {
 		return err
 	}
 
 	if !fileExists(dir + "vars.dart") {
-		err = ioutil.WriteFile(dir+"vars.dart", []byte(`const serverHost='demo-crm.xiaoheiban.cn';`), 0o644)
+		err = ioutil.WriteFile(dir+"vars.dart", []byte(fmt.Sprintf(`const serverHost='%s';`, hostname)), 0o644)
 		if err != nil {
 			return err
 		}
 	}
 
 	if !fileExists(dir + "kv.dart") {
-		err = ioutil.WriteFile(dir+"kv.dart", []byte(varTemplate), 0o644)
+		tpl := varTemplateV2
+		if isLegacy {
+			tpl = varTemplate
+		}
+		err = ioutil.WriteFile(dir+"kv.dart", []byte(tpl), 0o644)
 		if err != nil {
 			return err
 		}
diff --git a/tools/goctl/api/dartgen/util.go b/tools/goctl/api/dartgen/util.go
index 5e5fe7e3..0cccf36d 100644
--- a/tools/goctl/api/dartgen/util.go
+++ b/tools/goctl/api/dartgen/util.go
@@ -4,6 +4,7 @@ import (
 	"errors"
 	"fmt"
 	"os"
+	"path"
 	"strings"
 
 	"github.com/zeromicro/go-zero/tools/goctl/api/spec"
@@ -34,18 +35,16 @@ func pathToFuncName(path string) string {
 	return util.ToLower(camel[:1]) + camel[1:]
 }
 
-func tagGet(tag, k string) string {
-	tags, err := spec.Parse(tag)
-	if err != nil {
-		panic(k + " not exist")
-	}
+func getBaseName(str string) string {
+	return path.Base(str)
+}
 
-	v, err := tags.Get(k)
+func getPropertyFromMember(member spec.Member) string {
+	name, err := member.GetPropertyName()
 	if err != nil {
-		panic(k + " value not exist")
+		panic(fmt.Sprintf("cannot get property name of %q", member.Name))
 	}
-
-	return v.Name
+	return name
 }
 
 func isDirectType(s string) bool {
diff --git a/tools/goctl/api/dartgen/vars.go b/tools/goctl/api/dartgen/vars.go
index 78f95e1f..621a7c3a 100644
--- a/tools/goctl/api/dartgen/vars.go
+++ b/tools/goctl/api/dartgen/vars.go
@@ -3,12 +3,13 @@ package dartgen
 import "text/template"
 
 var funcMap = template.FuncMap{
-	"tagGet":          tagGet,
-	"isDirectType":    isDirectType,
-	"isClassListType": isClassListType,
-	"getCoreType":     getCoreType,
-	"pathToFuncName":  pathToFuncName,
-	"lowCamelCase":    lowCamelCase,
+	"getBaseName":           getBaseName,
+	"getPropertyFromMember": getPropertyFromMember,
+	"isDirectType":          isDirectType,
+	"isClassListType":       isClassListType,
+	"getCoreType":           getCoreType,
+	"pathToFuncName":        pathToFuncName,
+	"lowCamelCase":          lowCamelCase,
 }
 
 const (
@@ -99,6 +100,96 @@ Future _apiRequest(String method, String path, dynamic data,
 }
 `
 
+	apiFileContentV2 = `import 'dart:io';
+	import 'dart:convert';
+	import '../vars/kv.dart';
+	import '../vars/vars.dart';
+
+	/// send request with post method
+	///
+	/// data: any request class that will be converted to json automatically
+	/// ok: is called when request succeeds
+	/// fail: is called when request fails
+	/// eventually: is always called until the nearby functions returns
+	Future apiPost(String path, dynamic data,
+			{Map<String, String>? header,
+			Function(Map<String, dynamic>)? ok,
+			Function(String)? fail,
+			Function? eventually}) async {
+		await _apiRequest('POST', path, data,
+				header: header, ok: ok, fail: fail, eventually: eventually);
+	}
+
+	/// send request with get method
+	///
+	/// ok: is called when request succeeds
+	/// fail: is called when request fails
+	/// eventually: is always called until the nearby functions returns
+	Future apiGet(String path,
+			{Map<String, String>? header,
+			Function(Map<String, dynamic>)? ok,
+			Function(String)? fail,
+			Function? eventually}) async {
+		await _apiRequest('GET', path, null,
+				header: header, ok: ok, fail: fail, eventually: eventually);
+	}
+
+	Future _apiRequest(String method, String path, dynamic data,
+			{Map<String, String>? header,
+			Function(Map<String, dynamic>)? ok,
+			Function(String)? fail,
+			Function? eventually}) async {
+		var tokens = await getTokens();
+		try {
+			var client = HttpClient();
+			HttpClientRequest r;
+			if (method == 'POST') {
+				r = await client.postUrl(Uri.parse('https://' + serverHost + path));
+			} else {
+				r = await client.getUrl(Uri.parse('https://' + serverHost + path));
+			}
+
+			r.headers.set('Content-Type', 'application/json');
+			if (tokens != null) {
+				r.headers.set('Authorization', tokens.accessToken);
+			}
+			if (header != null) {
+				header.forEach((k, v) {
+					r.headers.set(k, v);
+				});
+			}
+			var strData = '';
+			if (data != null) {
+				strData = jsonEncode(data);
+			}
+			r.write(strData);
+			var rp = await r.close();
+			var body = await rp.transform(utf8.decoder).join();
+			print('${rp.statusCode} - $path');
+			print('-- request --');
+			print(strData);
+			print('-- response --');
+			print('$body \n');
+			if (rp.statusCode == 404) {
+				if (fail != null) fail('404 not found');
+			} else {
+				Map<String, dynamic> base = jsonDecode(body);
+				if (rp.statusCode == 200) {
+					if (base['code'] != 0) {
+						if (fail != null) fail(base['desc']);
+					} else {
+						if (ok != null) ok(base['data']);
+					}
+				} else if (base['code'] != 0) {
+					if (fail != null) fail(base['desc']);
+				}
+			}
+		} catch (e) {
+			if (fail != null) fail(e.toString());
+		}
+		if (eventually != null) eventually();
+	}`
+
 	tokensFileContent = `class Tokens {
   /// 用于访问的token, 每次请求都必须带在Header里面
   final String accessToken;
@@ -132,5 +223,41 @@ Future _apiRequest(String method, String path, dynamic data,
     };
   }
 }
+`
+
+	tokensFileContentV2 = `class Tokens {
+  /// 用于访问的token, 每次请求都必须带在Header里面
+  final String accessToken;
+  final int accessExpire;
+
+  /// 用于刷新token
+  final String refreshToken;
+  final int refreshExpire;
+  final int refreshAfter;
+  Tokens({
+		required this.accessToken,
+		required this.accessExpire,
+		required this.refreshToken,
+		required this.refreshExpire,
+		required this.refreshAfter
+	});
+  factory Tokens.fromJson(Map<String, dynamic> m) {
+    return Tokens(
+        accessToken: m['access_token'],
+        accessExpire: m['access_expire'],
+        refreshToken: m['refresh_token'],
+        refreshExpire: m['refresh_expire'],
+        refreshAfter: m['refresh_after']);
+  }
+  Map<String, dynamic> toJson() {
+    return {
+      'access_token': accessToken,
+      'access_expire': accessExpire,
+      'refresh_token': refreshToken,
+      'refresh_expire': refreshExpire,
+      'refresh_after': refreshAfter,
+    };
+  }
+}
 `
 )
diff --git a/tools/goctl/go.mod b/tools/goctl/go.mod
index bd61025f..ec1544b6 100644
--- a/tools/goctl/go.mod
+++ b/tools/goctl/go.mod
@@ -12,6 +12,6 @@ require (
 	github.com/stretchr/testify v1.7.0
 	github.com/urfave/cli v1.22.5
 	github.com/zeromicro/antlr v0.0.1
-	github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348
-	github.com/zeromicro/go-zero v1.3.0
+	github.com/zeromicro/ddl-parser v1.0.3
+	github.com/zeromicro/go-zero v1.3.1
 )
diff --git a/tools/goctl/go.sum b/tools/goctl/go.sum
index a3bbc0a8..1554883f 100644
--- a/tools/goctl/go.sum
+++ b/tools/goctl/go.sum
@@ -36,7 +36,6 @@ github.com/ClickHouse/clickhouse-go v1.5.1/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHg
 github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
 github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs=
@@ -54,13 +53,15 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd
 github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec h1:EEyRvzmpEUZ+I8WmD5cw/vY8EqhambkOqy5iFr0908A=
 github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -69,7 +70,6 @@ github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
-github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
@@ -82,6 +82,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
 github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@@ -97,7 +99,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
 github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -138,8 +139,8 @@ github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL9
 github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
 github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
-github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
+github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
@@ -173,7 +174,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -272,7 +272,6 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
-github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
 github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
@@ -329,7 +328,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
 github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
@@ -358,13 +356,13 @@ github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5u
 github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
 github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk=
 github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
-github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348 h1:OhxL9tn28gDeJVzreIUiE5oVxZCjL3tBJ0XBNw8p5R8=
-github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
-github.com/zeromicro/go-zero v1.3.0 h1:Eyn36yBtR043sm4YKmxR6eS3UA/GtZDktQ+UqIJ3Lm0=
-github.com/zeromicro/go-zero v1.3.0/go.mod h1:Hy4o1VFAt32lXaQMbaBhoFeZjA/rJqJ4PTGNdGsURcc=
-go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
-go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
-go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q=
+github.com/zeromicro/ddl-parser v1.0.3 h1:hFecpbt0oPQMhHAbqG1tz78MUepHUnOkFJp1dvRBFyc=
+github.com/zeromicro/ddl-parser v1.0.3/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
+github.com/zeromicro/go-zero v1.3.1 h1:uVkELq9kosgRZBSERb+eG7+oY2E+BEpOJW5vZZ354Cs=
+github.com/zeromicro/go-zero v1.3.1/go.mod h1:JsgCzJSUcjZl487xtqWHzYFa7Wl4f5Gi3lcteOWgNRA=
+go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
+go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/v3 v3.5.2/go.mod h1:kOOaWFFgHygyT0WlSmL8TJiXmMysO/nNUlEsSsN6W4o=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -379,12 +377,15 @@ go.opentelemetry.io/otel/trace v1.3.0 h1:doy8Hzb1RJ+I3yFhtDmwNc7tIyw1tNMOIsyPzp1
 go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
 go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
-go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
+go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -417,7 +418,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
 golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@@ -427,7 +427,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
 golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -460,8 +459,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
 golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d h1:1n1fc535VhN8SYtD4cDUyNlfpAF2ROMM9+11equK3hs=
-golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -521,9 +520,11 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
-golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
+golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -574,12 +575,10 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -617,7 +616,7 @@ google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfG
 google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
 google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20220112215332-a9c7c0acf9f2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20220228195345-15d65a4533f7/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -629,9 +628,8 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
 google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
 google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
-google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -643,7 +641,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/tools/goctl/goctl.go b/tools/goctl/goctl.go
index 77c23a28..f9af586a 100644
--- a/tools/goctl/goctl.go
+++ b/tools/goctl/goctl.go
@@ -266,6 +266,14 @@ var commands = []cli.Command{
 						Name:  "api",
 						Usage: "the api file",
 					},
+					cli.BoolFlag{
+						Name:  "legacy",
+						Usage: "legacy generator for flutter v1",
+					},
+					cli.StringFlag{
+						Name:  "hostname",
+						Usage: "hostname of the server",
+					},
 				},
 				Action: dartgen.DartCommand,
 			},
diff --git a/zrpc/proxy.go b/zrpc/proxy.go
index d02f7ff4..7bb997f8 100644
--- a/zrpc/proxy.go
+++ b/zrpc/proxy.go
@@ -12,20 +12,20 @@ import (
 
 // A RpcProxy is a rpc proxy.
 type RpcProxy struct {
-	backend     string
-	clients     map[string]Client
-	options     []internal.ClientOption
-	sharedCalls syncx.SingleFlight
-	lock        sync.Mutex
+	backend      string
+	clients      map[string]Client
+	options      []internal.ClientOption
+	singleFlight syncx.SingleFlight
+	lock         sync.Mutex
 }
 
 // NewProxy returns a RpcProxy.
 func NewProxy(backend string, opts ...internal.ClientOption) *RpcProxy {
 	return &RpcProxy{
-		backend:     backend,
-		clients:     make(map[string]Client),
-		options:     opts,
-		sharedCalls: syncx.NewSingleFlight(),
+		backend:      backend,
+		clients:      make(map[string]Client),
+		options:      opts,
+		singleFlight: syncx.NewSingleFlight(),
 	}
 }
 
@@ -33,7 +33,7 @@ func NewProxy(backend string, opts ...internal.ClientOption) *RpcProxy {
 func (p *RpcProxy) TakeConn(ctx context.Context) (*grpc.ClientConn, error) {
 	cred := auth.ParseCredential(ctx)
 	key := cred.App + "/" + cred.Token
-	val, err := p.sharedCalls.Do(key, func() (interface{}, error) {
+	val, err := p.singleFlight.Do(key, func() (interface{}, error) {
 		p.lock.Lock()
 		client, ok := p.clients[key]
 		p.lock.Unlock()


Test patch:
diff --git a/core/collection/fifo_test.go b/core/collection/fifo_test.go
index 3e58afef..6f1acfdf 100644
--- a/core/collection/fifo_test.go
+++ b/core/collection/fifo_test.go
@@ -61,3 +61,41 @@ func TestPutMore(t *testing.T) {
 		assert.Equal(t, string(element), string(body.([]byte)))
 	}
 }
+
+func TestPutMoreWithHeaderNotZero(t *testing.T) {
+	elements := [][]byte{
+		[]byte("hello"),
+		[]byte("world"),
+		[]byte("again"),
+	}
+	queue := NewQueue(4)
+	for i := range elements {
+		queue.Put(elements[i])
+	}
+
+	// take 1
+	body, ok := queue.Take()
+	assert.True(t, ok)
+	element, ok := body.([]byte)
+	assert.True(t, ok)
+	assert.Equal(t, element, []byte("hello"))
+
+	// put more
+	queue.Put([]byte("b4"))
+	queue.Put([]byte("b5")) // will store in elements[0]
+	queue.Put([]byte("b6")) // cause expansion
+
+	results := [][]byte{
+		[]byte("world"),
+		[]byte("again"),
+		[]byte("b4"),
+		[]byte("b5"),
+		[]byte("b6"),
+	}
+
+	for _, element := range results {
+		body, ok := queue.Take()
+		assert.True(t, ok)
+		assert.Equal(t, string(element), string(body.([]byte)))
+	}
+}
diff --git a/core/limit/periodlimit_test.go b/core/limit/periodlimit_test.go
index 8fc4403c..c23c14db 100644
--- a/core/limit/periodlimit_test.go
+++ b/core/limit/periodlimit_test.go
@@ -65,3 +65,13 @@ func testPeriodLimit(t *testing.T, opts ...PeriodOption) {
 	assert.Equal(t, 1, hitQuota)
 	assert.Equal(t, total-quota, overQuota)
 }
+
+func TestQuotaFull(t *testing.T) {
+	s, err := miniredis.Run()
+	assert.Nil(t, err)
+
+	l := NewPeriodLimit(1, 1, redis.New(s.Addr()), "periodlimit")
+	val, err := l.Take("first")
+	assert.Nil(t, err)
+	assert.Equal(t, HitQuota, val)
+}
diff --git a/core/logx/durationlogger_test.go b/core/logx/durationlogger_test.go
index 96eba091..4cebf448 100644
--- a/core/logx/durationlogger_test.go
+++ b/core/logx/durationlogger_test.go
@@ -3,6 +3,7 @@ package logx
 import (
 	"log"
 	"strings"
+	"sync/atomic"
 	"testing"
 	"time"
 
@@ -38,10 +39,10 @@ func TestWithDurationInfo(t *testing.T) {
 }
 
 func TestWithDurationInfoConsole(t *testing.T) {
-	old := encoding
-	encoding = plainEncodingType
+	old := atomic.LoadUint32(&encoding)
+	atomic.StoreUint32(&encoding, plainEncodingType)
 	defer func() {
-		encoding = old
+		atomic.StoreUint32(&encoding, old)
 	}()
 
 	var builder strings.Builder
diff --git a/core/logx/logs_test.go b/core/logx/logs_test.go
index 29d647c2..7ab86c52 100644
--- a/core/logx/logs_test.go
+++ b/core/logx/logs_test.go
@@ -145,10 +145,10 @@ func TestStructedLogInfoConsoleAny(t *testing.T) {
 	doTestStructedLogConsole(t, func(writer io.WriteCloser) {
 		infoLog = writer
 	}, func(v ...interface{}) {
-		old := encoding
-		encoding = plainEncodingType
+		old := atomic.LoadUint32(&encoding)
+		atomic.StoreUint32(&encoding, plainEncodingType)
 		defer func() {
-			encoding = old
+			atomic.StoreUint32(&encoding, old)
 		}()
 
 		Infov(v)
@@ -159,10 +159,10 @@ func TestStructedLogInfoConsoleAnyString(t *testing.T) {
 	doTestStructedLogConsole(t, func(writer io.WriteCloser) {
 		infoLog = writer
 	}, func(v ...interface{}) {
-		old := encoding
-		encoding = plainEncodingType
+		old := atomic.LoadUint32(&encoding)
+		atomic.StoreUint32(&encoding, plainEncodingType)
 		defer func() {
-			encoding = old
+			atomic.StoreUint32(&encoding, old)
 		}()
 
 		Infov(fmt.Sprint(v...))
@@ -173,10 +173,10 @@ func TestStructedLogInfoConsoleAnyError(t *testing.T) {
 	doTestStructedLogConsole(t, func(writer io.WriteCloser) {
 		infoLog = writer
 	}, func(v ...interface{}) {
-		old := encoding
-		encoding = plainEncodingType
+		old := atomic.LoadUint32(&encoding)
+		atomic.StoreUint32(&encoding, plainEncodingType)
 		defer func() {
-			encoding = old
+			atomic.StoreUint32(&encoding, old)
 		}()
 
 		Infov(errors.New(fmt.Sprint(v...)))
@@ -187,10 +187,10 @@ func TestStructedLogInfoConsoleAnyStringer(t *testing.T) {
 	doTestStructedLogConsole(t, func(writer io.WriteCloser) {
 		infoLog = writer
 	}, func(v ...interface{}) {
-		old := encoding
-		encoding = plainEncodingType
+		old := atomic.LoadUint32(&encoding)
+		atomic.StoreUint32(&encoding, plainEncodingType)
 		defer func() {
-			encoding = old
+			atomic.StoreUint32(&encoding, old)
 		}()
 
 		Infov(ValStringer{
@@ -203,10 +203,10 @@ func TestStructedLogInfoConsoleText(t *testing.T) {
 	doTestStructedLogConsole(t, func(writer io.WriteCloser) {
 		infoLog = writer
 	}, func(v ...interface{}) {
-		old := encoding
-		encoding = plainEncodingType
+		old := atomic.LoadUint32(&encoding)
+		atomic.StoreUint32(&encoding, plainEncodingType)
 		defer func() {
-			encoding = old
+			atomic.StoreUint32(&encoding, old)
 		}()
 
 		Info(fmt.Sprint(v...))
diff --git a/core/logx/syslog_test.go b/core/logx/syslog_test.go
index 01b285ee..d2a4fd29 100644
--- a/core/logx/syslog_test.go
+++ b/core/logx/syslog_test.go
@@ -29,9 +29,9 @@ func TestRedirector(t *testing.T) {
 }
 
 func captureOutput(f func()) string {
-	atomic.StoreUint32(&initialized, 1)
 	writer := new(mockWriter)
 	infoLog = writer
+	atomic.StoreUint32(&initialized, 1)
 
 	prevLevel := atomic.LoadUint32(&logLevel)
 	SetLevel(InfoLevel)
@@ -44,5 +44,9 @@ func captureOutput(f func()) string {
 func getContent(jsonStr string) string {
 	var entry logEntry
 	json.Unmarshal([]byte(jsonStr), &entry)
-	return entry.Content.(string)
+	val, ok := entry.Content.(string)
+	if ok {
+		return val
+	}
+	return ""
 }
diff --git a/core/logx/tracelogger_test.go b/core/logx/tracelogger_test.go
index 7da8d0dd..3fa4d2ed 100644
--- a/core/logx/tracelogger_test.go
+++ b/core/logx/tracelogger_test.go
@@ -83,10 +83,10 @@ func TestTraceInfo(t *testing.T) {
 }
 
 func TestTraceInfoConsole(t *testing.T) {
-	old := encoding
-	encoding = plainEncodingType
+	old := atomic.LoadUint32(&encoding)
+	atomic.StoreUint32(&encoding, jsonEncodingType)
 	defer func() {
-		encoding = old
+		atomic.StoreUint32(&encoding, old)
 	}()
 
 	var buf mockWriter
diff --git a/core/stores/mongoc/cachedcollection_test.go b/core/stores/mongoc/cachedcollection_test.go
index 6f839b13..f7eaa254 100644
--- a/core/stores/mongoc/cachedcollection_test.go
+++ b/core/stores/mongoc/cachedcollection_test.go
@@ -34,7 +34,7 @@ func TestCollection_Count(t *testing.T) {
 	assert.Nil(t, err)
 	defer clean()
 
-	cach := cache.NewNode(r, sharedCalls, stats, mgo.ErrNotFound)
+	cach := cache.NewNode(r, singleFlight, stats, mgo.ErrNotFound)
 	c := newCollection(dummyConn{}, cach)
 	val, err := c.Count("any")
 	assert.Nil(t, err)
@@ -98,7 +98,7 @@ func TestStat(t *testing.T) {
 	assert.Nil(t, err)
 	defer clean()
 
-	cach := cache.NewNode(r, sharedCalls, stats, mgo.ErrNotFound)
+	cach := cache.NewNode(r, singleFlight, stats, mgo.ErrNotFound)
 	c := newCollection(dummyConn{}, cach).(*cachedCollection)
 
 	for i := 0; i < 10; i++ {
@@ -121,7 +121,7 @@ func TestStatCacheFails(t *testing.T) {
 	defer log.SetOutput(os.Stdout)
 
 	r := redis.New("localhost:59999")
-	cach := cache.NewNode(r, sharedCalls, stats, mgo.ErrNotFound)
+	cach := cache.NewNode(r, singleFlight, stats, mgo.ErrNotFound)
 	c := newCollection(dummyConn{}, cach)
 
 	for i := 0; i < 20; i++ {
@@ -142,7 +142,7 @@ func TestStatDbFails(t *testing.T) {
 	assert.Nil(t, err)
 	defer clean()
 
-	cach := cache.NewNode(r, sharedCalls, stats, mgo.ErrNotFound)
+	cach := cache.NewNode(r, singleFlight, stats, mgo.ErrNotFound)
 	c := newCollection(dummyConn{}, cach).(*cachedCollection)
 
 	for i := 0; i < 20; i++ {
@@ -164,7 +164,7 @@ func TestStatFromMemory(t *testing.T) {
 	assert.Nil(t, err)
 	defer clean()
 
-	cach := cache.NewNode(r, sharedCalls, stats, mgo.ErrNotFound)
+	cach := cache.NewNode(r, singleFlight, stats, mgo.ErrNotFound)
 	c := newCollection(dummyConn{}, cach).(*cachedCollection)
 
 	var all sync.WaitGroup
diff --git a/tools/goctl/api/dartgen/util_test.go b/tools/goctl/api/dartgen/util_test.go
new file mode 100644
index 00000000..68a221fd
--- /dev/null
+++ b/tools/goctl/api/dartgen/util_test.go
@@ -0,0 +1,39 @@
+package dartgen
+
+import (
+	"testing"
+
+	"github.com/zeromicro/go-zero/tools/goctl/api/spec"
+)
+
+func Test_getPropertyFromMember(t *testing.T) {
+	tests := []struct {
+		name   string
+		member spec.Member
+		want   string
+	}{
+		{
+			name: "json tag should be ok",
+			member: spec.Member{
+				Tag:  "`json:\"foo\"`",
+				Name: "Foo",
+			},
+			want: "foo",
+		},
+		{
+			name: "form tag should be ok",
+			member: spec.Member{
+				Tag:  "`form:\"bar\"`",
+				Name: "Bar",
+			},
+			want: "bar",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := getPropertyFromMember(tt.member); got != tt.want {
+				t.Errorf("getPropertyFromMember() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/tools/goctl/api/parser/g4/gen/api/file_splitor_test.go b/tools/goctl/api/parser/g4/gen/api/file_splitor_test.go
index ab7f0682..541d6cbe 100644
--- a/tools/goctl/api/parser/g4/gen/api/file_splitor_test.go
+++ b/tools/goctl/api/parser/g4/gen/api/file_splitor_test.go
@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
+	"go/format"
 	"io/ioutil"
 	"log"
 	"os"
@@ -61,7 +62,12 @@ import "github.com/zeromicro/antlr"
 			}
 		}
 
-		err = ioutil.WriteFile(fp, buffer.Bytes(), os.ModePerm)
+		src, err := format.Source(buffer.Bytes())
+		if err != nil {
+			fmt.Printf("%+v\n", err)
+			break
+		}
+		err = ioutil.WriteFile(fp, src, os.ModePerm)
 		if err != nil {
 			fmt.Printf("%+v\n", err)
 		}
diff --git a/tools/goctl/model/sql/test/sqlconn.go b/tools/goctl/model/sql/test/sqlconn.go
index 2a1a55cb..b02e3854 100644
--- a/tools/goctl/model/sql/test/sqlconn.go
+++ b/tools/goctl/model/sql/test/sqlconn.go
@@ -3,6 +3,7 @@
 package mocksql
 
 import (
+	"context"
 	"database/sql"
 
 	"github.com/zeromicro/go-zero/core/stores/sqlx"
@@ -29,12 +30,22 @@ func (conn *MockConn) Exec(query string, args ...interface{}) (sql.Result, error
 	return exec(conn.db, query, args...)
 }
 
+// ExecCtx executes sql and returns the result
+func (conn *MockConn) ExecCtx(_ context.Context, query string, args ...interface{}) (sql.Result, error) {
+	return exec(conn.db, query, args...)
+}
+
 // Prepare executes sql by sql.DB
 func (conn *MockConn) Prepare(query string) (sqlx.StmtSession, error) {
 	st, err := conn.db.Prepare(query)
 	return statement{stmt: st}, err
 }
 
+// PrepareCtx executes sql by sql.DB
+func (conn *MockConn) PrepareCtx(_ context.Context, query string) (sqlx.StmtSession, error) {
+	return conn.Prepare(query)
+}
+
 // QueryRow executes sql and returns a query row
 func (conn *MockConn) QueryRow(v interface{}, q string, args ...interface{}) error {
 	return query(conn.db, func(rows *sql.Rows) error {
@@ -42,6 +53,11 @@ func (conn *MockConn) QueryRow(v interface{}, q string, args ...interface{}) err
 	}, q, args...)
 }
 
+// QueryRowCtx executes sql and returns a query row
+func (conn *MockConn) QueryRowCtx(_ context.Context, v interface{}, query string, args ...interface{}) error {
+	return conn.QueryRow(v, query, args...)
+}
+
 // QueryRowPartial executes sql and returns a partial query row
 func (conn *MockConn) QueryRowPartial(v interface{}, q string, args ...interface{}) error {
 	return query(conn.db, func(rows *sql.Rows) error {
@@ -49,6 +65,11 @@ func (conn *MockConn) QueryRowPartial(v interface{}, q string, args ...interface
 	}, q, args...)
 }
 
+// QueryRowPartialCtx executes sql and returns a partial query row
+func (conn *MockConn) QueryRowPartialCtx(_ context.Context, v interface{}, query string, args ...interface{}) error {
+	return conn.QueryRowPartial(v, query, args...)
+}
+
 // QueryRows executes sql and returns  query rows
 func (conn *MockConn) QueryRows(v interface{}, q string, args ...interface{}) error {
 	return query(conn.db, func(rows *sql.Rows) error {
@@ -56,6 +77,11 @@ func (conn *MockConn) QueryRows(v interface{}, q string, args ...interface{}) er
 	}, q, args...)
 }
 
+// QueryRowsCtx executes sql and returns  query rows
+func (conn *MockConn) QueryRowsCtx(_ context.Context, v interface{}, query string, args ...interface{}) error {
+	return conn.QueryRows(v, query, args...)
+}
+
 // QueryRowsPartial executes sql and returns partial query rows
 func (conn *MockConn) QueryRowsPartial(v interface{}, q string, args ...interface{}) error {
 	return query(conn.db, func(rows *sql.Rows) error {
@@ -63,6 +89,11 @@ func (conn *MockConn) QueryRowsPartial(v interface{}, q string, args ...interfac
 	}, q, args...)
 }
 
+// QueryRowsPartialCtx executes sql and returns partial query rows
+func (conn *MockConn) QueryRowsPartialCtx(_ context.Context, v interface{}, query string, args ...interface{}) error {
+	return conn.QueryRowsPartial(v, query, args...)
+}
+
 // RawDB returns the underlying sql.DB.
 func (conn *MockConn) RawDB() (*sql.DB, error) {
 	return conn.db, nil
@@ -73,6 +104,11 @@ func (conn *MockConn) Transact(func(session sqlx.Session) error) error {
 	return nil
 }
 
+// TransactCtx is the implemention of sqlx.SqlConn, nothing to do
+func (conn *MockConn) TransactCtx(ctx context.Context, fn func(context.Context, sqlx.Session) error) error {
+	return nil
+}
+
 func (s statement) Close() error {
 	return s.stmt.Close()
 }
@@ -81,26 +117,46 @@ func (s statement) Exec(args ...interface{}) (sql.Result, error) {
 	return execStmt(s.stmt, args...)
 }
 
+func (s statement) ExecCtx(_ context.Context, args ...interface{}) (sql.Result, error) {
+	return s.Exec(args...)
+}
+
 func (s statement) QueryRow(v interface{}, args ...interface{}) error {
 	return queryStmt(s.stmt, func(rows *sql.Rows) error {
 		return unmarshalRow(v, rows, true)
 	}, args...)
 }
 
+func (s statement) QueryRowCtx(_ context.Context, v interface{}, args ...interface{}) error {
+	return s.QueryRow(v, args...)
+}
+
 func (s statement) QueryRowPartial(v interface{}, args ...interface{}) error {
 	return queryStmt(s.stmt, func(rows *sql.Rows) error {
 		return unmarshalRow(v, rows, false)
 	}, args...)
 }
 
+func (s statement) QueryRowPartialCtx(_ context.Context, v interface{}, args ...interface{}) error {
+	return s.QueryRowPartial(v, args...)
+}
+
 func (s statement) QueryRows(v interface{}, args ...interface{}) error {
 	return queryStmt(s.stmt, func(rows *sql.Rows) error {
 		return unmarshalRows(v, rows, true)
 	}, args...)
 }
 
+func (s statement) QueryRowsCtx(_ context.Context, v interface{}, args ...interface{}) error {
+	return s.QueryRows(v, args...)
+}
+
 func (s statement) QueryRowsPartial(v interface{}, args ...interface{}) error {
 	return queryStmt(s.stmt, func(rows *sql.Rows) error {
 		return unmarshalRows(v, rows, false)
 	}, args...)
 }
+
+func (s statement) QueryRowsPartialCtx(_ context.Context, v interface{}, args ...interface{}) error {
+	return s.QueryRowsPartial(v, args...)
+}
diff --git a/zrpc/proxy_test.go b/zrpc/proxy_test.go
index 97a24fe4..935914a4 100644
--- a/zrpc/proxy_test.go
+++ b/zrpc/proxy_test.go
@@ -64,3 +64,9 @@ func TestProxy(t *testing.T) {
 		})
 	}
 }
+
+func TestRpcProxy_TakeConnNewClientFailed(t *testing.T) {
+	proxy := NewProxy("foo", WithDialOption(grpc.WithInsecure()), WithDialOption(grpc.WithBlock()))
+	_, err := proxy.TakeConn(context.Background())
+	assert.NotNil(t, err)
+}
diff --git a/zrpc/server_test.go b/zrpc/server_test.go
index 5dad1b99..14360ccc 100644
--- a/zrpc/server_test.go
+++ b/zrpc/server_test.go
@@ -101,6 +101,21 @@ func TestServer_HasEtcd(t *testing.T) {
 	srv.Stop()
 }
 
+func TestServer_StartFailed(t *testing.T) {
+	srv := MustNewServer(RpcServerConf{
+		ServiceConf: service.ServiceConf{
+			Log: logx.LogConf{
+				ServiceName: "foo",
+				Mode:        "console",
+			},
+		},
+		ListenOn: "localhost:aaa",
+	}, func(server *grpc.Server) {
+	})
+
+	assert.Panics(t, srv.Start)
+}
+
 type mockedServer struct {
 	unaryInterceptors  []grpc.UnaryServerInterceptor
 	streamInterceptors []grpc.StreamServerInterceptor