Compare commits

..

32 Commits

Author SHA1 Message Date
Kevin Wan
6deb80625d fix issue of default migrate version (#1536)
* fix issue of default migrate version

* chore: update console colors
2022-02-14 23:09:32 +08:00
Kevin Wan
6ab051568c Update readme-cn.md
add go-zero users
2022-02-14 16:57:48 +08:00
Kevin Wan
2732d3cdae chore: refactor cache (#1532) 2022-02-13 18:04:31 +08:00
chenquan
e8c307e4dc feat: support ctx in Cache (#1518)
* feature: support ctx in `Cache`

Signed-off-by: chenquan <chenquan.dev@foxmail.com>

* fix: `errors.Is` instead of `=`

Signed-off-by: chenquan <chenquan.dev@foxmail.com>
2022-02-13 17:28:14 +08:00
Kevin Wan
84ddc660c4 chore: goctl format issue (#1531) 2022-02-13 13:17:19 +08:00
Kevin Wan
e60e707955 upgrade grpc version (#1530) 2022-02-12 23:58:41 +08:00
Kevin Wan
cf4321b2d0 fix #1525 (#1527) 2022-02-11 23:04:57 +08:00
chenquan
1993faf2f8 fix: fix a typo (#1522)
Signed-off-by: chenquan <chenquan.dev@foxmail.com>
2022-02-11 21:15:45 +08:00
Kevin Wan
0ce85376bf chore: update goctl version to 1.3.2 (#1524) 2022-02-11 21:02:50 +08:00
Kevin Wan
a40254156f refactor: refactor yaml unmarshaler (#1517) 2022-02-09 17:22:52 +08:00
chenquan
05cc62f5ff chore: optimize yaml unmarshaler (#1513) 2022-02-09 16:57:00 +08:00
chenquan
9c2c90e533 chore: make error clearer (#1514) 2022-02-09 14:40:05 +08:00
Kevin Wan
822ee2e1c5 feat: update go-redis to v8, support ctx in redis methods (#1507)
* feat: update go-redis to v8, support ctx in redis methods

* fix compile errors

* chore: remove unused const

* chore: add tracing log on redis
2022-02-09 11:06:06 +08:00
anqiansong
77482c8946 fixes typo (#1511)
Co-authored-by: anqiansong <anqiansong@bytedance.com>
2022-02-08 22:16:38 +08:00
Kevin Wan
7ef0ab3119 Update readme-cn.md 2022-02-08 11:47:33 +08:00
anqiansong
8bd89a297a feature: Add goctl completion (#1505)
* feature: Add `goctl completion`

* Update const

Co-authored-by: anqiansong <anqiansong@bytedance.com>
2022-02-08 10:50:21 +08:00
Kevin Wan
bb75cc796e test: change fuzz tests (#1504) 2022-02-05 09:44:01 +08:00
Kevin Wan
0fdd8f54eb ci: add test for win (#1503)
* ci: add test for win

* ci: update check names

* ci: use go build instead of go test to verify win test

* fix: windows test failure

* chore: disable logs in tests
2022-02-05 00:06:23 +08:00
anqiansong
b1ffc464cd fix typo: goctl protoc usage (#1502)
Co-authored-by: anqiansong <anqiansong@bytedance.com>
2022-02-03 22:13:02 +08:00
Kevin Wan
50174960e4 chore: update command comment (#1501) 2022-02-02 22:02:08 +08:00
Kevin Wan
8f46eab977 fix: goctl not compile on windows (#1500) 2022-02-01 13:58:08 +08:00
Kevin Wan
ec299085f5 docs: update tal-tech to zeromico in docs (#1498) 2022-02-01 13:03:30 +08:00
Kevin Wan
7727d70634 chore: update goctl version (#1497) 2022-02-01 09:50:26 +08:00
Kevin Wan
5f9d101bc6 feat: add runtime stats monitor (#1496) 2022-02-01 01:34:25 +08:00
Kevin Wan
6c2abe7474 fix: goroutine stuck on edge case (#1495)
* fix: goroutine stuck on edge case

* refactor: simplify mapreduce implementation
2022-01-30 13:09:21 +08:00
Kevin Wan
14a902c1a7 feat: handling panic in mapreduce, panic in calling goroutine, not inside goroutines (#1490)
* feat: handle panic

* chore: update fuzz test

* chore: optimize square sum algorithm
2022-01-28 10:59:41 +08:00
Kevin Wan
5ad6a6d229 Update readme-cn.md
add slogan
2022-01-27 17:16:30 +08:00
Kevin Wan
6f4b97864a chore: improve migrate confirmation (#1488) 2022-01-27 11:30:35 +08:00
Kevin Wan
0e0abc3a95 chore: update warning message (#1487) 2022-01-26 23:47:57 +08:00
anqiansong
696fda1db4 patch: goctl migrate (#1485)
* * Add signal check
* Add deprecated pkg check

* fix typo `replacementBuilderx`

* output to console if verbose

Co-authored-by: anqiansong <anqiansong@bytedance.com>
2022-01-26 23:24:25 +08:00
Kevin Wan
c1d2634427 chore: update go version for goctl (#1484) 2022-01-26 14:27:43 +08:00
Kevin Wan
4b7a680ac5 refactor: rename from tal-tech to zeromicro for goctl (#1481) 2022-01-25 23:15:07 +08:00
196 changed files with 2764 additions and 1185 deletions

View File

@@ -7,32 +7,50 @@ on:
branches: [ master ]
jobs:
build:
name: Build
test-linux:
name: Linux
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
id: go
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Get dependencies
run: |
go get -v -t -d ./...
- name: Get dependencies
run: |
go get -v -t -d ./...
- name: Lint
run: |
go vet -stdmethods=false $(go list ./...)
go install mvdan.cc/gofumpt@latest
test -z "$(gofumpt -s -l -extra .)" || echo "Please run 'gofumpt -l -w -extra .'"
- name: Lint
run: |
go vet -stdmethods=false $(go list ./...)
go install mvdan.cc/gofumpt@latest
test -z "$(gofumpt -s -l -extra .)" || echo "Please run 'gofumpt -l -w -extra .'"
- name: Test
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Test
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Codecov
uses: codecov/codecov-action@v2
- name: Codecov
uses: codecov/codecov-action@v2
test-win:
name: Windows
runs-on: windows-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
- name: Checkout codebase
uses: actions/checkout@v2
- name: Test
run: |
go mod verify
go mod download
go test -v -race ./...
cd tools/goctl && go build -v goctl.go

3
.gitignore vendored
View File

@@ -16,7 +16,8 @@
**/logs
# for test purpose
adhoc
**/adhoc
**/testdata
# gitlab ci
.cache

View File

@@ -2,6 +2,13 @@ package discov
import "errors"
var (
// errEmptyEtcdHosts indicates that etcd hosts are empty.
errEmptyEtcdHosts = errors.New("empty etcd hosts")
// errEmptyEtcdKey indicates that etcd key is empty.
errEmptyEtcdKey = errors.New("empty etcd key")
)
// EtcdConf is the config item with the given key on etcd.
type EtcdConf struct {
Hosts []string
@@ -27,9 +34,9 @@ func (c EtcdConf) HasTLS() bool {
// Validate validates c.
func (c EtcdConf) Validate() error {
if len(c.Hosts) == 0 {
return errors.New("empty etcd hosts")
return errEmptyEtcdHosts
} else if len(c.Key) == 0 {
return errors.New("empty etcd key")
return errEmptyEtcdKey
} else {
return nil
}

View File

@@ -5,6 +5,9 @@ import (
"os"
)
// errExceedFileSize indicates that the file size is exceeded.
var errExceedFileSize = errors.New("exceed file size")
// A RangeReader is used to read a range of content from a file.
type RangeReader struct {
file *os.File
@@ -29,7 +32,7 @@ func (rr *RangeReader) Read(p []byte) (n int, err error) {
}
if rr.stop < rr.start || rr.start >= stat.Size() {
return 0, errors.New("exceed file size")
return 0, errExceedFileSize
}
if rr.stop-rr.start < int64(len(p)) {

View File

@@ -51,5 +51,5 @@ func unmarshalUseNumber(decoder *json.Decoder, v interface{}) error {
}
func formatError(v string, err error) error {
return fmt.Errorf("string: `%s`, error: `%s`", v, err.Error())
return fmt.Errorf("string: `%s`, error: `%w`", v, err)
}

View File

@@ -23,10 +23,9 @@ func TestPeriodLimit_RedisUnavailable(t *testing.T) {
const (
seconds = 1
total = 100
quota = 5
)
l := NewPeriodLimit(seconds, quota, redis.NewRedis(s.Addr(), redis.NodeType), "periodlimit")
l := NewPeriodLimit(seconds, quota, redis.New(s.Addr()), "periodlimit")
s.Close()
val, err := l.Take("first")
assert.NotNil(t, err)

View File

@@ -72,7 +72,7 @@ var (
// ErrLogServiceNameNotSet is an error that indicates that the service name is not set.
ErrLogServiceNameNotSet = errors.New("log service name must be set")
timeFormat = "2006-01-02T15:04:05.000Z07"
timeFormat = "2006-01-02T15:04:05.000Z07:00"
writeConsole bool
logLevel uint32
encoding = jsonEncodingType

View File

@@ -4,7 +4,6 @@ import (
"encoding/json"
"errors"
"io"
"io/ioutil"
"gopkg.in/yaml.v2"
)
@@ -14,7 +13,7 @@ const yamlTagKey = "json"
var (
// ErrUnsupportedType is an error that indicates the config format is not supported.
ErrUnsupportedType = errors.New("only map-like configs are suported")
ErrUnsupportedType = errors.New("only map-like configs are supported")
yamlUnmarshaler = NewUnmarshaler(yamlTagKey)
)
@@ -29,39 +28,6 @@ func UnmarshalYamlReader(reader io.Reader, v interface{}) error {
return unmarshalYamlReader(reader, v, yamlUnmarshaler)
}
func unmarshalYamlBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error {
var o interface{}
if err := yamlUnmarshal(content, &o); err != nil {
return err
}
if m, ok := o.(map[string]interface{}); ok {
return unmarshaler.Unmarshal(m, v)
}
return ErrUnsupportedType
}
func unmarshalYamlReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error {
content, err := ioutil.ReadAll(reader)
if err != nil {
return err
}
return unmarshalYamlBytes(content, v, unmarshaler)
}
// yamlUnmarshal YAML to map[string]interface{} instead of map[interface{}]interface{}.
func yamlUnmarshal(in []byte, out interface{}) error {
var res interface{}
if err := yaml.Unmarshal(in, &res); err != nil {
return err
}
*out.(*interface{}) = cleanupMapValue(res)
return nil
}
func cleanupInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
res := make(map[string]interface{})
for k, v := range in {
@@ -96,3 +62,40 @@ func cleanupMapValue(v interface{}) interface{} {
return Repr(v)
}
}
func unmarshal(unmarshaler *Unmarshaler, o interface{}, v interface{}) error {
if m, ok := o.(map[string]interface{}); ok {
return unmarshaler.Unmarshal(m, v)
}
return ErrUnsupportedType
}
func unmarshalYamlBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error {
var o interface{}
if err := yamlUnmarshal(content, &o); err != nil {
return err
}
return unmarshal(unmarshaler, o, v)
}
func unmarshalYamlReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error {
var res interface{}
if err := yaml.NewDecoder(reader).Decode(&res); err != nil {
return err
}
return unmarshal(unmarshaler, cleanupMapValue(res), v)
}
// yamlUnmarshal YAML to map[string]interface{} instead of map[interface{}]interface{}.
func yamlUnmarshal(in []byte, out interface{}) error {
var res interface{}
if err := yaml.Unmarshal(in, &res); err != nil {
return err
}
*out.(*interface{}) = cleanupMapValue(res)
return nil
}

View File

@@ -926,14 +926,18 @@ func TestUnmarshalYamlBytesError(t *testing.T) {
}
func TestUnmarshalYamlReaderError(t *testing.T) {
payload := `abcd: cdef`
reader := strings.NewReader(payload)
var v struct {
Any string
}
reader := strings.NewReader(`abcd: cdef`)
err := UnmarshalYamlReader(reader, &v)
assert.NotNil(t, err)
reader = strings.NewReader("chenquan")
err = UnmarshalYamlReader(reader, &v)
assert.ErrorIs(t, err, ErrUnsupportedType)
}
func TestUnmarshalYamlBadReader(t *testing.T) {
@@ -1011,6 +1015,6 @@ func TestUnmarshalYamlMapRune(t *testing.T) {
type badReader struct{}
func (b *badReader) Read(p []byte) (n int, err error) {
func (b *badReader) Read(_ []byte) (n int, err error) {
return 0, io.ErrLimitReached
}

View File

@@ -3,12 +3,11 @@ package mr
import (
"context"
"errors"
"fmt"
"sync"
"sync/atomic"
"github.com/zeromicro/go-zero/core/errorx"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/threading"
)
const (
@@ -42,6 +41,16 @@ type (
// Option defines the method to customize the mapreduce.
Option func(opts *mapReduceOptions)
mapperContext struct {
ctx context.Context
mapper MapFunc
source <-chan interface{}
panicChan *onceChan
collector chan<- interface{}
doneChan <-chan lang.PlaceholderType
workers int
}
mapReduceOptions struct {
ctx context.Context
workers int
@@ -90,46 +99,72 @@ func FinishVoid(fns ...func()) {
// ForEach maps all elements from given generate but no output.
func ForEach(generate GenerateFunc, mapper ForEachFunc, opts ...Option) {
drain(Map(generate, func(item interface{}, writer Writer) {
mapper(item)
}, opts...))
}
// Map maps all elements generated from given generate func, and returns an output channel.
func Map(generate GenerateFunc, mapper MapFunc, opts ...Option) chan interface{} {
options := buildOptions(opts...)
source := buildSource(generate)
panicChan := &onceChan{channel: make(chan interface{})}
source := buildSource(generate, panicChan)
collector := make(chan interface{}, options.workers)
done := make(chan lang.PlaceholderType)
go executeMappers(options.ctx, mapper, source, collector, done, options.workers)
go executeMappers(mapperContext{
ctx: options.ctx,
mapper: func(item interface{}, writer Writer) {
mapper(item)
},
source: source,
panicChan: panicChan,
collector: collector,
doneChan: done,
workers: options.workers,
})
return collector
for {
select {
case v := <-panicChan.channel:
panic(v)
case _, ok := <-collector:
if !ok {
return
}
}
}
}
// MapReduce maps all elements generated from given generate func,
// and reduces the output elements with given reducer.
func MapReduce(generate GenerateFunc, mapper MapperFunc, reducer ReducerFunc,
opts ...Option) (interface{}, error) {
source := buildSource(generate)
return MapReduceChan(source, mapper, reducer, opts...)
panicChan := &onceChan{channel: make(chan interface{})}
source := buildSource(generate, panicChan)
return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...)
}
// MapReduceChan maps all elements from source, and reduce the output elements with given reducer.
func MapReduceChan(source <-chan interface{}, mapper MapperFunc, reducer ReducerFunc,
opts ...Option) (interface{}, error) {
panicChan := &onceChan{channel: make(chan interface{})}
return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...)
}
// MapReduceChan maps all elements from source, and reduce the output elements with given reducer.
func mapReduceWithPanicChan(source <-chan interface{}, panicChan *onceChan, mapper MapperFunc,
reducer ReducerFunc, opts ...Option) (interface{}, error) {
options := buildOptions(opts...)
// output is used to write the final result
output := make(chan interface{})
defer func() {
// reducer can only write once, if more, panic
for range output {
panic("more than one element written in reducer")
}
}()
// collector is used to collect data from mapper, and consume in reducer
collector := make(chan interface{}, options.workers)
// if done is closed, all mappers and reducer should stop processing
done := make(chan lang.PlaceholderType)
writer := newGuardedWriter(options.ctx, output, done)
var closeOnce sync.Once
// use atomic.Value to avoid data race
var retErr errorx.AtomicError
finish := func() {
closeOnce.Do(func() {
@@ -151,30 +186,38 @@ func MapReduceChan(source <-chan interface{}, mapper MapperFunc, reducer Reducer
go func() {
defer func() {
drain(collector)
if r := recover(); r != nil {
cancel(fmt.Errorf("%v", r))
} else {
finish()
panicChan.write(r)
}
finish()
}()
reducer(collector, writer, cancel)
}()
go executeMappers(options.ctx, func(item interface{}, w Writer) {
mapper(item, w, cancel)
}, source, collector, done, options.workers)
go executeMappers(mapperContext{
ctx: options.ctx,
mapper: func(item interface{}, w Writer) {
mapper(item, w, cancel)
},
source: source,
panicChan: panicChan,
collector: collector,
doneChan: done,
workers: options.workers,
})
select {
case <-options.ctx.Done():
cancel(context.DeadlineExceeded)
return nil, context.DeadlineExceeded
case value, ok := <-output:
case v := <-panicChan.channel:
panic(v)
case v, ok := <-output:
if err := retErr.Load(); err != nil {
return nil, err
} else if ok {
return value, nil
return v, nil
} else {
return nil, ErrReduceNoOutput
}
@@ -221,12 +264,18 @@ func buildOptions(opts ...Option) *mapReduceOptions {
return options
}
func buildSource(generate GenerateFunc) chan interface{} {
func buildSource(generate GenerateFunc, panicChan *onceChan) chan interface{} {
source := make(chan interface{})
threading.GoSafe(func() {
defer close(source)
go func() {
defer func() {
if r := recover(); r != nil {
panicChan.write(r)
}
close(source)
}()
generate(source)
})
}()
return source
}
@@ -238,39 +287,43 @@ func drain(channel <-chan interface{}) {
}
}
func executeMappers(ctx context.Context, mapper MapFunc, input <-chan interface{},
collector chan<- interface{}, done <-chan lang.PlaceholderType, workers int) {
func executeMappers(mCtx mapperContext) {
var wg sync.WaitGroup
defer func() {
wg.Wait()
close(collector)
close(mCtx.collector)
drain(mCtx.source)
}()
pool := make(chan lang.PlaceholderType, workers)
writer := newGuardedWriter(ctx, collector, done)
for {
var failed int32
pool := make(chan lang.PlaceholderType, mCtx.workers)
writer := newGuardedWriter(mCtx.ctx, mCtx.collector, mCtx.doneChan)
for atomic.LoadInt32(&failed) == 0 {
select {
case <-ctx.Done():
case <-mCtx.ctx.Done():
return
case <-done:
case <-mCtx.doneChan:
return
case pool <- lang.Placeholder:
item, ok := <-input
item, ok := <-mCtx.source
if !ok {
<-pool
return
}
wg.Add(1)
// better to safely run caller defined method
threading.GoSafe(func() {
go func() {
defer func() {
if r := recover(); r != nil {
atomic.AddInt32(&failed, 1)
mCtx.panicChan.write(r)
}
wg.Done()
<-pool
}()
mapper(item, writer)
})
mCtx.mapper(item, writer)
}()
}
}
}
@@ -316,3 +369,16 @@ func (gw guardedWriter) Write(v interface{}) {
gw.channel <- v
}
}
type onceChan struct {
channel chan interface{}
wrote int32
}
func (oc *onceChan) write(val interface{}) {
if atomic.AddInt32(&oc.wrote, 1) > 1 {
return
}
oc.channel <- val
}

View File

@@ -0,0 +1,78 @@
//go:build go1.18
// +build go1.18
package mr
import (
"fmt"
"math/rand"
"runtime"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"go.uber.org/goleak"
)
func FuzzMapReduce(f *testing.F) {
rand.Seed(time.Now().UnixNano())
f.Add(uint(10), uint(runtime.NumCPU()))
f.Fuzz(func(t *testing.T, num uint, workers uint) {
n := int64(num)%5000 + 5000
genPanic := rand.Intn(100) == 0
mapperPanic := rand.Intn(100) == 0
reducerPanic := rand.Intn(100) == 0
genIdx := rand.Int63n(n)
mapperIdx := rand.Int63n(n)
reducerIdx := rand.Int63n(n)
squareSum := (n - 1) * n * (2*n - 1) / 6
fn := func() (interface{}, error) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())
return MapReduce(func(source chan<- interface{}) {
for i := int64(0); i < n; i++ {
source <- i
if genPanic && i == genIdx {
panic("foo")
}
}
}, func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int64)
if mapperPanic && v == mapperIdx {
panic("bar")
}
writer.Write(v * v)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var idx int64
var total int64
for v := range pipe {
if reducerPanic && idx == reducerIdx {
panic("baz")
}
total += v.(int64)
idx++
}
writer.Write(total)
}, WithWorkers(int(workers)%50+runtime.NumCPU()/2))
}
if genPanic || mapperPanic || reducerPanic {
var buf strings.Builder
buf.WriteString(fmt.Sprintf("n: %d", n))
buf.WriteString(fmt.Sprintf(", genPanic: %t", genPanic))
buf.WriteString(fmt.Sprintf(", mapperPanic: %t", mapperPanic))
buf.WriteString(fmt.Sprintf(", reducerPanic: %t", reducerPanic))
buf.WriteString(fmt.Sprintf(", genIdx: %d", genIdx))
buf.WriteString(fmt.Sprintf(", mapperIdx: %d", mapperIdx))
buf.WriteString(fmt.Sprintf(", reducerIdx: %d", reducerIdx))
assert.Panicsf(t, func() { fn() }, buf.String())
} else {
val, err := fn()
assert.Nil(t, err)
assert.Equal(t, squareSum, val.(int64))
}
})
}

View File

@@ -0,0 +1,107 @@
//go:build fuzz
// +build fuzz
package mr
import (
"fmt"
"math/rand"
"runtime"
"strconv"
"strings"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/threading"
"gopkg.in/cheggaaa/pb.v1"
)
// If Fuzz stuck, we don't know why, because it only returns hung or unexpected,
// so we need to simulate the fuzz test in test mode.
func TestMapReduceRandom(t *testing.T) {
rand.Seed(time.Now().UnixNano())
const (
times = 10000
nRange = 500
mega = 1024 * 1024
)
bar := pb.New(times).Start()
runner := threading.NewTaskRunner(runtime.NumCPU())
var wg sync.WaitGroup
wg.Add(times)
for i := 0; i < times; i++ {
runner.Schedule(func() {
start := time.Now()
defer func() {
if time.Since(start) > time.Minute {
t.Fatal("timeout")
}
wg.Done()
}()
t.Run(strconv.Itoa(i), func(t *testing.T) {
n := rand.Int63n(nRange)%nRange + nRange
workers := rand.Int()%50 + runtime.NumCPU()/2
genPanic := rand.Intn(100) == 0
mapperPanic := rand.Intn(100) == 0
reducerPanic := rand.Intn(100) == 0
genIdx := rand.Int63n(n)
mapperIdx := rand.Int63n(n)
reducerIdx := rand.Int63n(n)
squareSum := (n - 1) * n * (2*n - 1) / 6
fn := func() (interface{}, error) {
return MapReduce(func(source chan<- interface{}) {
for i := int64(0); i < n; i++ {
source <- i
if genPanic && i == genIdx {
panic("foo")
}
}
}, func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int64)
if mapperPanic && v == mapperIdx {
panic("bar")
}
writer.Write(v * v)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var idx int64
var total int64
for v := range pipe {
if reducerPanic && idx == reducerIdx {
panic("baz")
}
total += v.(int64)
idx++
}
writer.Write(total)
}, WithWorkers(int(workers)%50+runtime.NumCPU()/2))
}
if genPanic || mapperPanic || reducerPanic {
var buf strings.Builder
buf.WriteString(fmt.Sprintf("n: %d", n))
buf.WriteString(fmt.Sprintf(", genPanic: %t", genPanic))
buf.WriteString(fmt.Sprintf(", mapperPanic: %t", mapperPanic))
buf.WriteString(fmt.Sprintf(", reducerPanic: %t", reducerPanic))
buf.WriteString(fmt.Sprintf(", genIdx: %d", genIdx))
buf.WriteString(fmt.Sprintf(", mapperIdx: %d", mapperIdx))
buf.WriteString(fmt.Sprintf(", reducerIdx: %d", reducerIdx))
assert.Panicsf(t, func() { fn() }, buf.String())
} else {
val, err := fn()
assert.Nil(t, err)
assert.Equal(t, squareSum, val.(int64))
}
bar.Increment()
})
})
}
wg.Wait()
bar.Finish()
}

View File

@@ -11,8 +11,6 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/zeromicro/go-zero/core/syncx"
"go.uber.org/goleak"
)
@@ -124,84 +122,69 @@ func TestForEach(t *testing.T) {
t.Run("all", func(t *testing.T) {
defer goleak.VerifyNone(t)
ForEach(func(source chan<- interface{}) {
for i := 0; i < tasks; i++ {
source <- i
}
}, func(item interface{}) {
panic("foo")
assert.PanicsWithValue(t, "foo", func() {
ForEach(func(source chan<- interface{}) {
for i := 0; i < tasks; i++ {
source <- i
}
}, func(item interface{}) {
panic("foo")
})
})
})
}
func TestMap(t *testing.T) {
func TestGeneratePanic(t *testing.T) {
defer goleak.VerifyNone(t)
tests := []struct {
mapper MapFunc
expect int
}{
{
mapper: func(item interface{}, writer Writer) {
v := item.(int)
writer.Write(v * v)
},
expect: 30,
},
{
mapper: func(item interface{}, writer Writer) {
v := item.(int)
if v%2 == 0 {
return
}
writer.Write(v * v)
},
expect: 10,
},
{
mapper: func(item interface{}, writer Writer) {
v := item.(int)
if v%2 == 0 {
panic(v)
}
writer.Write(v * v)
},
expect: 10,
},
}
t.Run("all", func(t *testing.T) {
assert.PanicsWithValue(t, "foo", func() {
ForEach(func(source chan<- interface{}) {
panic("foo")
}, func(item interface{}) {
})
})
})
}
for _, test := range tests {
t.Run(stringx.Rand(), func(t *testing.T) {
channel := Map(func(source chan<- interface{}) {
for i := 1; i < 5; i++ {
func TestMapperPanic(t *testing.T) {
defer goleak.VerifyNone(t)
const tasks = 1000
var run int32
t.Run("all", func(t *testing.T) {
assert.PanicsWithValue(t, "foo", func() {
_, _ = MapReduce(func(source chan<- interface{}) {
for i := 0; i < tasks; i++ {
source <- i
}
}, test.mapper, WithWorkers(-1))
var result int
for v := range channel {
result += v.(int)
}
assert.Equal(t, test.expect, result)
}, func(item interface{}, writer Writer, cancel func(error)) {
atomic.AddInt32(&run, 1)
panic("foo")
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
})
})
}
assert.True(t, atomic.LoadInt32(&run) < tasks/2)
})
}
func TestMapReduce(t *testing.T) {
defer goleak.VerifyNone(t)
tests := []struct {
name string
mapper MapperFunc
reducer ReducerFunc
expectErr error
expectValue interface{}
}{
{
name: "simple",
expectErr: nil,
expectValue: 30,
},
{
name: "cancel with error",
mapper: func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int)
if v%3 == 0 {
@@ -212,6 +195,7 @@ func TestMapReduce(t *testing.T) {
expectErr: errDummy,
},
{
name: "cancel with nil",
mapper: func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int)
if v%3 == 0 {
@@ -223,6 +207,7 @@ func TestMapReduce(t *testing.T) {
expectValue: nil,
},
{
name: "cancel with more",
reducer: func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var result int
for item := range pipe {
@@ -237,45 +222,68 @@ func TestMapReduce(t *testing.T) {
},
}
for _, test := range tests {
t.Run(stringx.Rand(), func(t *testing.T) {
if test.mapper == nil {
test.mapper = func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int)
writer.Write(v * v)
}
}
if test.reducer == nil {
test.reducer = func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var result int
for item := range pipe {
result += item.(int)
t.Run("MapReduce", func(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.mapper == nil {
test.mapper = func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int)
writer.Write(v * v)
}
writer.Write(result)
}
}
value, err := MapReduce(func(source chan<- interface{}) {
for i := 1; i < 5; i++ {
source <- i
if test.reducer == nil {
test.reducer = func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var result int
for item := range pipe {
result += item.(int)
}
writer.Write(result)
}
}
}, test.mapper, test.reducer, WithWorkers(runtime.NumCPU()))
value, err := MapReduce(func(source chan<- interface{}) {
for i := 1; i < 5; i++ {
source <- i
}
}, test.mapper, test.reducer, WithWorkers(runtime.NumCPU()))
assert.Equal(t, test.expectErr, err)
assert.Equal(t, test.expectValue, value)
})
}
}
assert.Equal(t, test.expectErr, err)
assert.Equal(t, test.expectValue, value)
})
}
})
func TestMapReducePanicBothMapperAndReducer(t *testing.T) {
defer goleak.VerifyNone(t)
t.Run("MapReduce", func(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.mapper == nil {
test.mapper = func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int)
writer.Write(v * v)
}
}
if test.reducer == nil {
test.reducer = func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var result int
for item := range pipe {
result += item.(int)
}
writer.Write(result)
}
}
_, _ = MapReduce(func(source chan<- interface{}) {
source <- 0
source <- 1
}, func(item interface{}, writer Writer, cancel func(error)) {
panic("foo")
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
panic("bar")
source := make(chan interface{})
go func() {
for i := 1; i < 5; i++ {
source <- i
}
close(source)
}()
value, err := MapReduceChan(source, test.mapper, test.reducer, WithWorkers(-1))
assert.Equal(t, test.expectErr, err)
assert.Equal(t, test.expectValue, value)
})
}
})
}
@@ -302,16 +310,19 @@ func TestMapReduceVoid(t *testing.T) {
var value uint32
tests := []struct {
name string
mapper MapperFunc
reducer VoidReducerFunc
expectValue uint32
expectErr error
}{
{
name: "simple",
expectValue: 30,
expectErr: nil,
},
{
name: "cancel with error",
mapper: func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int)
if v%3 == 0 {
@@ -322,6 +333,7 @@ func TestMapReduceVoid(t *testing.T) {
expectErr: errDummy,
},
{
name: "cancel with nil",
mapper: func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int)
if v%3 == 0 {
@@ -332,6 +344,7 @@ func TestMapReduceVoid(t *testing.T) {
expectErr: ErrCancelWithNil,
},
{
name: "cancel with more",
reducer: func(pipe <-chan interface{}, cancel func(error)) {
for item := range pipe {
result := atomic.AddUint32(&value, uint32(item.(int)))
@@ -345,7 +358,7 @@ func TestMapReduceVoid(t *testing.T) {
}
for _, test := range tests {
t.Run(stringx.Rand(), func(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
atomic.StoreUint32(&value, 0)
if test.mapper == nil {
@@ -400,39 +413,59 @@ func TestMapReduceVoidWithDelay(t *testing.T) {
assert.Equal(t, 0, result[1])
}
func TestMapVoid(t *testing.T) {
defer goleak.VerifyNone(t)
const tasks = 1000
var count uint32
ForEach(func(source chan<- interface{}) {
for i := 0; i < tasks; i++ {
source <- i
}
}, func(item interface{}) {
atomic.AddUint32(&count, 1)
})
assert.Equal(t, tasks, int(count))
}
func TestMapReducePanic(t *testing.T) {
defer goleak.VerifyNone(t)
v, err := MapReduce(func(source chan<- interface{}) {
source <- 0
source <- 1
}, func(item interface{}, writer Writer, cancel func(error)) {
i := item.(int)
writer.Write(i)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
for range pipe {
panic("panic")
}
assert.Panics(t, func() {
_, _ = MapReduce(func(source chan<- interface{}) {
source <- 0
source <- 1
}, func(item interface{}, writer Writer, cancel func(error)) {
i := item.(int)
writer.Write(i)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
for range pipe {
panic("panic")
}
})
})
}
func TestMapReducePanicOnce(t *testing.T) {
defer goleak.VerifyNone(t)
assert.Panics(t, func() {
_, _ = MapReduce(func(source chan<- interface{}) {
for i := 0; i < 100; i++ {
source <- i
}
}, func(item interface{}, writer Writer, cancel func(error)) {
i := item.(int)
if i == 0 {
panic("foo")
}
writer.Write(i)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
for range pipe {
panic("bar")
}
})
})
}
func TestMapReducePanicBothMapperAndReducer(t *testing.T) {
defer goleak.VerifyNone(t)
assert.Panics(t, func() {
_, _ = MapReduce(func(source chan<- interface{}) {
source <- 0
source <- 1
}, func(item interface{}, writer Writer, cancel func(error)) {
panic("foo")
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
panic("bar")
})
})
assert.Nil(t, v)
assert.NotNil(t, err)
assert.Equal(t, "panic", err.Error())
}
func TestMapReduceVoidCancel(t *testing.T) {
@@ -461,13 +494,13 @@ func TestMapReduceVoidCancel(t *testing.T) {
func TestMapReduceVoidCancelWithRemains(t *testing.T) {
defer goleak.VerifyNone(t)
var done syncx.AtomicBool
var done int32
var result []int
err := MapReduceVoid(func(source chan<- interface{}) {
for i := 0; i < defaultWorkers*2; i++ {
source <- i
}
done.Set(true)
atomic.AddInt32(&done, 1)
}, func(item interface{}, writer Writer, cancel func(error)) {
i := item.(int)
if i == defaultWorkers/2 {
@@ -482,7 +515,7 @@ func TestMapReduceVoidCancelWithRemains(t *testing.T) {
})
assert.NotNil(t, err)
assert.Equal(t, "anything", err.Error())
assert.True(t, done.True())
assert.Equal(t, int32(1), done)
}
func TestMapReduceWithoutReducerWrite(t *testing.T) {
@@ -507,34 +540,51 @@ func TestMapReduceVoidPanicInReducer(t *testing.T) {
defer goleak.VerifyNone(t)
const message = "foo"
var done syncx.AtomicBool
err := MapReduceVoid(func(source chan<- interface{}) {
assert.Panics(t, func() {
var done int32
_ = MapReduceVoid(func(source chan<- interface{}) {
for i := 0; i < defaultWorkers*2; i++ {
source <- i
}
atomic.AddInt32(&done, 1)
}, func(item interface{}, writer Writer, cancel func(error)) {
i := item.(int)
writer.Write(i)
}, func(pipe <-chan interface{}, cancel func(error)) {
panic(message)
}, WithWorkers(1))
})
}
func TestForEachWithContext(t *testing.T) {
defer goleak.VerifyNone(t)
var done int32
ctx, cancel := context.WithCancel(context.Background())
ForEach(func(source chan<- interface{}) {
for i := 0; i < defaultWorkers*2; i++ {
source <- i
}
done.Set(true)
}, func(item interface{}, writer Writer, cancel func(error)) {
atomic.AddInt32(&done, 1)
}, func(item interface{}) {
i := item.(int)
writer.Write(i)
}, func(pipe <-chan interface{}, cancel func(error)) {
panic(message)
}, WithWorkers(1))
assert.NotNil(t, err)
assert.Equal(t, message, err.Error())
assert.True(t, done.True())
if i == defaultWorkers/2 {
cancel()
}
}, WithContext(ctx))
}
func TestMapReduceWithContext(t *testing.T) {
defer goleak.VerifyNone(t)
var done syncx.AtomicBool
var done int32
var result []int
ctx, cancel := context.WithCancel(context.Background())
err := MapReduceVoid(func(source chan<- interface{}) {
for i := 0; i < defaultWorkers*2; i++ {
source <- i
}
done.Set(true)
atomic.AddInt32(&done, 1)
}, func(item interface{}, writer Writer, c func(error)) {
i := item.(int)
if i == defaultWorkers/2 {

View File

@@ -54,7 +54,7 @@ import (
"fmt"
"log"
"github.com/tal-tech/go-zero/core/mr"
"github.com/zeromicro/go-zero/core/mr"
)
func main() {

View File

@@ -55,7 +55,7 @@ import (
"fmt"
"log"
"github.com/tal-tech/go-zero/core/mr"
"github.com/zeromicro/go-zero/core/mr"
)
func main() {
@@ -87,4 +87,4 @@ More examples: [https://github.com/zeromicro/zero-examples/tree/main/mapreduce](
## Give a Star! ⭐
If you like or are using this project to learn or start your solution, please give it a star. Thanks!
If you like or are using this project to learn or start your solution, please give it a star. Thanks!

View File

@@ -1,3 +1,6 @@
//go:build linux || darwin
// +build linux darwin
package proc
import (

30
core/prof/runtime.go Normal file
View File

@@ -0,0 +1,30 @@
package prof
import (
"fmt"
"runtime"
"time"
)
const (
defaultInterval = time.Second * 5
mega = 1024 * 1024
)
func DisplayStats(interval ...time.Duration) {
duration := defaultInterval
for _, val := range interval {
duration = val
}
go func() {
ticker := time.NewTicker(duration)
defer ticker.Stop()
for range ticker.C {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Goroutines: %d, Alloc: %vm, TotalAlloc: %vm, Sys: %vm, NumGC: %v\n",
runtime.NumGoroutine(), m.Alloc/mega, m.TotalAlloc/mega, m.Sys/mega, m.NumGC)
}
}()
}

View File

@@ -1,6 +1,8 @@
package cache
import (
"context"
"errors"
"fmt"
"log"
"time"
@@ -13,13 +15,37 @@ import (
type (
// Cache interface is used to define the cache implementation.
Cache interface {
// Del deletes cached values with keys.
Del(keys ...string) error
Get(key string, v interface{}) error
// DelCtx deletes cached values with keys.
DelCtx(ctx context.Context, keys ...string) error
// Get gets the cache with key and fills into v.
Get(key string, val interface{}) error
// GetCtx gets the cache with key and fills into v.
GetCtx(ctx context.Context, key string, val interface{}) error
// IsNotFound checks if the given error is the defined errNotFound.
IsNotFound(err error) bool
Set(key string, v interface{}) error
SetWithExpire(key string, v interface{}, expire time.Duration) error
Take(v interface{}, key string, query func(v interface{}) error) error
TakeWithExpire(v interface{}, key string, query func(v interface{}, expire time.Duration) error) error
// Set sets the cache with key and v, using c.expiry.
Set(key string, val interface{}) error
// SetCtx sets the cache with key and v, using c.expiry.
SetCtx(ctx context.Context, key string, val interface{}) error
// SetWithExpire sets the cache with key and v, using given expire.
SetWithExpire(key string, val interface{}, expire time.Duration) error
// SetWithExpireCtx sets the cache with key and v, using given expire.
SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error
// Take takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
Take(val interface{}, key string, query func(val interface{}) error) error
// TakeCtx takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error
// TakeWithExpire takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result.
TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error
// TakeWithExpireCtx takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result.
TakeWithExpireCtx(ctx context.Context, val interface{}, key string,
query func(val interface{}, expire time.Duration) error) error
}
cacheCluster struct {
@@ -51,7 +77,13 @@ func New(c ClusterConf, barrier syncx.SingleFlight, st *Stat, errNotFound error,
}
}
// Del deletes cached values with keys.
func (cc cacheCluster) Del(keys ...string) error {
return cc.DelCtx(context.Background(), keys...)
}
// DelCtx deletes cached values with keys.
func (cc cacheCluster) DelCtx(ctx context.Context, keys ...string) error {
switch len(keys) {
case 0:
return nil
@@ -62,7 +94,7 @@ func (cc cacheCluster) Del(keys ...string) error {
return cc.errNotFound
}
return c.(Cache).Del(key)
return c.(Cache).DelCtx(ctx, key)
default:
var be errorx.BatchError
nodes := make(map[interface{}][]string)
@@ -76,7 +108,7 @@ func (cc cacheCluster) Del(keys ...string) error {
nodes[c] = append(nodes[c], key)
}
for c, ks := range nodes {
if err := c.(Cache).Del(ks...); err != nil {
if err := c.(Cache).DelCtx(ctx, ks...); err != nil {
be.Add(err)
}
}
@@ -85,52 +117,86 @@ func (cc cacheCluster) Del(keys ...string) error {
}
}
func (cc cacheCluster) Get(key string, v interface{}) error {
// Get gets the cache with key and fills into v.
func (cc cacheCluster) Get(key string, val interface{}) error {
return cc.GetCtx(context.Background(), key, val)
}
// GetCtx gets the cache with key and fills into v.
func (cc cacheCluster) GetCtx(ctx context.Context, key string, val interface{}) error {
c, ok := cc.dispatcher.Get(key)
if !ok {
return cc.errNotFound
}
return c.(Cache).Get(key, v)
return c.(Cache).GetCtx(ctx, key, val)
}
// IsNotFound checks if the given error is the defined errNotFound.
func (cc cacheCluster) IsNotFound(err error) bool {
return err == cc.errNotFound
return errors.Is(err, cc.errNotFound)
}
func (cc cacheCluster) Set(key string, v interface{}) error {
// Set sets the cache with key and v, using c.expiry.
func (cc cacheCluster) Set(key string, val interface{}) error {
return cc.SetCtx(context.Background(), key, val)
}
// SetCtx sets the cache with key and v, using c.expiry.
func (cc cacheCluster) SetCtx(ctx context.Context, key string, val interface{}) error {
c, ok := cc.dispatcher.Get(key)
if !ok {
return cc.errNotFound
}
return c.(Cache).Set(key, v)
return c.(Cache).SetCtx(ctx, key, val)
}
func (cc cacheCluster) SetWithExpire(key string, v interface{}, expire time.Duration) error {
// SetWithExpire sets the cache with key and v, using given expire.
func (cc cacheCluster) SetWithExpire(key string, val interface{}, expire time.Duration) error {
return cc.SetWithExpireCtx(context.Background(), key, val, expire)
}
// SetWithExpireCtx sets the cache with key and v, using given expire.
func (cc cacheCluster) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error {
c, ok := cc.dispatcher.Get(key)
if !ok {
return cc.errNotFound
}
return c.(Cache).SetWithExpire(key, v, expire)
return c.(Cache).SetWithExpireCtx(ctx, key, val, expire)
}
func (cc cacheCluster) Take(v interface{}, key string, query func(v interface{}) error) error {
// Take takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
func (cc cacheCluster) Take(val interface{}, key string, query func(val interface{}) error) error {
return cc.TakeCtx(context.Background(), val, key, query)
}
// TakeCtx takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
func (cc cacheCluster) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error {
c, ok := cc.dispatcher.Get(key)
if !ok {
return cc.errNotFound
}
return c.(Cache).Take(v, key, query)
return c.(Cache).TakeCtx(ctx, val, key, query)
}
func (cc cacheCluster) TakeWithExpire(v interface{}, key string,
query func(v interface{}, expire time.Duration) error) error {
// TakeWithExpire takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result.
func (cc cacheCluster) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
return cc.TakeWithExpireCtx(context.Background(), val, key, query)
}
// TakeWithExpireCtx takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result.
func (cc cacheCluster) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
c, ok := cc.dispatcher.Get(key)
if !ok {
return cc.errNotFound
}
return c.(Cache).TakeWithExpire(v, key, query)
return c.(Cache).TakeWithExpireCtx(ctx, val, key, query)
}

View File

@@ -1,7 +1,9 @@
package cache
import (
"context"
"encoding/json"
"errors"
"fmt"
"math"
"strconv"
@@ -16,12 +18,18 @@ import (
"github.com/zeromicro/go-zero/core/syncx"
)
var _ Cache = (*mockedNode)(nil)
type mockedNode struct {
vals map[string][]byte
errNotFound error
}
func (mc *mockedNode) Del(keys ...string) error {
return mc.DelCtx(context.Background(), keys...)
}
func (mc *mockedNode) DelCtx(_ context.Context, keys ...string) error {
var be errorx.BatchError
for _, key := range keys {
@@ -35,21 +43,29 @@ func (mc *mockedNode) Del(keys ...string) error {
return be.Err()
}
func (mc *mockedNode) Get(key string, v interface{}) error {
func (mc *mockedNode) Get(key string, val interface{}) error {
return mc.GetCtx(context.Background(), key, val)
}
func (mc *mockedNode) GetCtx(ctx context.Context, key string, val interface{}) error {
bs, ok := mc.vals[key]
if ok {
return json.Unmarshal(bs, v)
return json.Unmarshal(bs, val)
}
return mc.errNotFound
}
func (mc *mockedNode) IsNotFound(err error) bool {
return err == mc.errNotFound
return errors.Is(err, mc.errNotFound)
}
func (mc *mockedNode) Set(key string, v interface{}) error {
data, err := json.Marshal(v)
func (mc *mockedNode) Set(key string, val interface{}) error {
return mc.SetCtx(context.Background(), key, val)
}
func (mc *mockedNode) SetCtx(ctx context.Context, key string, val interface{}) error {
data, err := json.Marshal(val)
if err != nil {
return err
}
@@ -58,25 +74,37 @@ func (mc *mockedNode) Set(key string, v interface{}) error {
return nil
}
func (mc *mockedNode) SetWithExpire(key string, v interface{}, expire time.Duration) error {
return mc.Set(key, v)
func (mc *mockedNode) SetWithExpire(key string, val interface{}, expire time.Duration) error {
return mc.SetWithExpireCtx(context.Background(), key, val, expire)
}
func (mc *mockedNode) Take(v interface{}, key string, query func(v interface{}) error) error {
func (mc *mockedNode) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error {
return mc.Set(key, val)
}
func (mc *mockedNode) Take(val interface{}, key string, query func(val interface{}) error) error {
return mc.TakeCtx(context.Background(), val, key, query)
}
func (mc *mockedNode) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error {
if _, ok := mc.vals[key]; ok {
return mc.Get(key, v)
return mc.GetCtx(ctx, key, val)
}
if err := query(v); err != nil {
if err := query(val); err != nil {
return err
}
return mc.Set(key, v)
return mc.SetCtx(ctx, key, val)
}
func (mc *mockedNode) TakeWithExpire(v interface{}, key string, query func(v interface{}, expire time.Duration) error) error {
return mc.Take(v, key, func(v interface{}) error {
return query(v, 0)
func (mc *mockedNode) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
return mc.TakeWithExpireCtx(context.Background(), val, key, query)
}
func (mc *mockedNode) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
return mc.Take(val, key, func(val interface{}) error {
return query(val, 0)
})
}
@@ -113,18 +141,18 @@ func TestCache_SetDel(t *testing.T) {
}
}
for i := 0; i < total; i++ {
var v int
assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &v))
assert.Equal(t, i, v)
var val int
assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &val))
assert.Equal(t, i, val)
}
assert.Nil(t, c.Del())
for i := 0; i < total; i++ {
assert.Nil(t, c.Del(fmt.Sprintf("key/%d", i)))
}
for i := 0; i < total; i++ {
var v int
assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &v)))
assert.Equal(t, 0, v)
var val int
assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &val)))
assert.Equal(t, 0, val)
}
}
@@ -151,18 +179,18 @@ func TestCache_OneNode(t *testing.T) {
}
}
for i := 0; i < total; i++ {
var v int
assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &v))
assert.Equal(t, i, v)
var val int
assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &val))
assert.Equal(t, i, val)
}
assert.Nil(t, c.Del())
for i := 0; i < total; i++ {
assert.Nil(t, c.Del(fmt.Sprintf("key/%d", i)))
}
for i := 0; i < total; i++ {
var v int
assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &v)))
assert.Equal(t, 0, v)
var val int
assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &val)))
assert.Equal(t, 0, val)
}
}
@@ -202,9 +230,9 @@ func TestCache_Balance(t *testing.T) {
assert.True(t, entropy > .95, fmt.Sprintf("entropy should be greater than 0.95, but got %.2f", entropy))
for i := 0; i < total; i++ {
var v int
assert.Nil(t, c.Get(strconv.Itoa(i), &v))
assert.Equal(t, i, v)
var val int
assert.Nil(t, c.Get(strconv.Itoa(i), &val))
assert.Equal(t, i, val)
}
for i := 0; i < total/10; i++ {
@@ -216,14 +244,14 @@ func TestCache_Balance(t *testing.T) {
for i := 0; i < total/10; i++ {
var val int
if i%2 == 0 {
assert.Nil(t, c.Take(&val, strconv.Itoa(i*10), func(v interface{}) error {
*v.(*int) = i
assert.Nil(t, c.Take(&val, strconv.Itoa(i*10), func(val interface{}) error {
*val.(*int) = i
count++
return nil
}))
} else {
assert.Nil(t, c.TakeWithExpire(&val, strconv.Itoa(i*10), func(v interface{}, expire time.Duration) error {
*v.(*int) = i
assert.Nil(t, c.TakeWithExpire(&val, strconv.Itoa(i*10), func(val interface{}, expire time.Duration) error {
*val.(*int) = i
count++
return nil
}))
@@ -244,10 +272,10 @@ func TestCacheNoNode(t *testing.T) {
assert.NotNil(t, c.Get("foo", nil))
assert.NotNil(t, c.Set("foo", nil))
assert.NotNil(t, c.SetWithExpire("foo", nil, time.Second))
assert.NotNil(t, c.Take(nil, "foo", func(v interface{}) error {
assert.NotNil(t, c.Take(nil, "foo", func(val interface{}) error {
return nil
}))
assert.NotNil(t, c.TakeWithExpire(nil, "foo", func(v interface{}, duration time.Duration) error {
assert.NotNil(t, c.TakeWithExpire(nil, "foo", func(val interface{}, duration time.Duration) error {
return nil
}))
}
@@ -255,8 +283,8 @@ func TestCacheNoNode(t *testing.T) {
func calcEntropy(m map[int]int, total int) float64 {
var entropy float64
for _, v := range m {
proba := float64(v) / float64(total)
for _, val := range m {
proba := float64(val) / float64(total)
entropy -= proba * math.Log2(proba)
}

View File

@@ -1,6 +1,7 @@
package cache
import (
"context"
"errors"
"fmt"
"math/rand"
@@ -61,30 +62,39 @@ func NewNode(rds *redis.Redis, barrier syncx.SingleFlight, st *Stat,
// Del deletes cached values with keys.
func (c cacheNode) Del(keys ...string) error {
return c.DelCtx(context.Background(), keys...)
}
// DelCtx deletes cached values with keys.
func (c cacheNode) DelCtx(ctx context.Context, keys ...string) error {
if len(keys) == 0 {
return nil
}
logger := logx.WithContext(ctx)
if len(keys) > 1 && c.rds.Type == redis.ClusterType {
for _, key := range keys {
if _, err := c.rds.Del(key); err != nil {
logx.Errorf("failed to clear cache with key: %q, error: %v", key, err)
if _, err := c.rds.DelCtx(ctx, key); err != nil {
logger.Errorf("failed to clear cache with key: %q, error: %v", key, err)
c.asyncRetryDelCache(key)
}
}
} else {
if _, err := c.rds.Del(keys...); err != nil {
logx.Errorf("failed to clear cache with keys: %q, error: %v", formatKeys(keys), err)
c.asyncRetryDelCache(keys...)
}
} else if _, err := c.rds.DelCtx(ctx, keys...); err != nil {
logger.Errorf("failed to clear cache with keys: %q, error: %v", formatKeys(keys), err)
c.asyncRetryDelCache(keys...)
}
return nil
}
// Get gets the cache with key and fills into v.
func (c cacheNode) Get(key string, v interface{}) error {
err := c.doGetCache(key, v)
func (c cacheNode) Get(key string, val interface{}) error {
return c.GetCtx(context.Background(), key, val)
}
// GetCtx gets the cache with key and fills into v.
func (c cacheNode) GetCtx(ctx context.Context, key string, val interface{}) error {
err := c.doGetCache(ctx, key, val)
if err == errPlaceholder {
return c.errNotFound
}
@@ -94,22 +104,32 @@ func (c cacheNode) Get(key string, v interface{}) error {
// IsNotFound checks if the given error is the defined errNotFound.
func (c cacheNode) IsNotFound(err error) bool {
return err == c.errNotFound
return errors.Is(err, c.errNotFound)
}
// Set sets the cache with key and v, using c.expiry.
func (c cacheNode) Set(key string, v interface{}) error {
return c.SetWithExpire(key, v, c.aroundDuration(c.expiry))
func (c cacheNode) Set(key string, val interface{}) error {
return c.SetCtx(context.Background(), key, val)
}
// SetCtx sets the cache with key and v, using c.expiry.
func (c cacheNode) SetCtx(ctx context.Context, key string, val interface{}) error {
return c.SetWithExpireCtx(ctx, key, val, c.aroundDuration(c.expiry))
}
// SetWithExpire sets the cache with key and v, using given expire.
func (c cacheNode) SetWithExpire(key string, v interface{}, expire time.Duration) error {
data, err := jsonx.Marshal(v)
func (c cacheNode) SetWithExpire(key string, val interface{}, expire time.Duration) error {
return c.SetWithExpireCtx(context.Background(), key, val, expire)
}
// SetWithExpireCtx sets the cache with key and v, using given expire.
func (c cacheNode) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error {
data, err := jsonx.Marshal(val)
if err != nil {
return err
}
return c.rds.Setex(key, string(data), int(expire.Seconds()))
return c.rds.SetexCtx(ctx, key, string(data), int(expire.Seconds()))
}
// String returns a string that represents the cacheNode.
@@ -119,21 +139,32 @@ func (c cacheNode) String() string {
// Take takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
func (c cacheNode) Take(v interface{}, key string, query func(v interface{}) error) error {
return c.doTake(v, key, query, func(v interface{}) error {
return c.Set(key, v)
func (c cacheNode) Take(val interface{}, key string, query func(val interface{}) error) error {
return c.TakeCtx(context.Background(), val, key, query)
}
// TakeCtx takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
func (c cacheNode) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error {
return c.doTake(ctx, val, key, query, func(v interface{}) error {
return c.SetCtx(ctx, key, v)
})
}
// TakeWithExpire takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result.
func (c cacheNode) TakeWithExpire(v interface{}, key string, query func(v interface{},
expire time.Duration) error) error {
func (c cacheNode) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
return c.TakeWithExpireCtx(context.Background(), val, key, query)
}
// TakeWithExpireCtx takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result.
func (c cacheNode) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
expire := c.aroundDuration(c.expiry)
return c.doTake(v, key, func(v interface{}) error {
return c.doTake(ctx, val, key, func(v interface{}) error {
return query(v, expire)
}, func(v interface{}) error {
return c.SetWithExpire(key, v, expire)
return c.SetWithExpireCtx(ctx, key, v, expire)
})
}
@@ -148,9 +179,9 @@ func (c cacheNode) asyncRetryDelCache(keys ...string) {
}, keys...)
}
func (c cacheNode) doGetCache(key string, v interface{}) error {
func (c cacheNode) doGetCache(ctx context.Context, key string, v interface{}) error {
c.stat.IncrementTotal()
data, err := c.rds.Get(key)
data, err := c.rds.GetCtx(ctx, key)
if err != nil {
c.stat.IncrementMiss()
return err
@@ -166,13 +197,14 @@ func (c cacheNode) doGetCache(key string, v interface{}) error {
return errPlaceholder
}
return c.processCache(key, data, v)
return c.processCache(ctx, key, data, v)
}
func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) error,
cacheVal func(v interface{}) error) error {
func (c cacheNode) doTake(ctx context.Context, v interface{}, key string,
query func(v interface{}) error, cacheVal func(v interface{}) error) error {
logger := logx.WithContext(ctx)
val, fresh, err := c.barrier.DoEx(key, func() (interface{}, error) {
if err := c.doGetCache(key, v); err != nil {
if err := c.doGetCache(ctx, key, v); err != nil {
if err == errPlaceholder {
return nil, c.errNotFound
} else if err != c.errNotFound {
@@ -183,8 +215,8 @@ func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) e
}
if err = query(v); err == c.errNotFound {
if err = c.setCacheWithNotFound(key); err != nil {
logx.Error(err)
if err = c.setCacheWithNotFound(ctx, key); err != nil {
logger.Error(err)
}
return nil, c.errNotFound
@@ -194,7 +226,7 @@ func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) e
}
if err = cacheVal(v); err != nil {
logx.Error(err)
logger.Error(err)
}
}
@@ -214,7 +246,7 @@ func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) e
return jsonx.Unmarshal(val.([]byte), v)
}
func (c cacheNode) processCache(key, data string, v interface{}) error {
func (c cacheNode) processCache(ctx context.Context, key, data string, v interface{}) error {
err := jsonx.Unmarshal([]byte(data), v)
if err == nil {
return nil
@@ -222,10 +254,11 @@ func (c cacheNode) processCache(key, data string, v interface{}) error {
report := fmt.Sprintf("unmarshal cache, node: %s, key: %s, value: %s, error: %v",
c.rds.Addr, key, data, err)
logx.Error(report)
logger := logx.WithContext(ctx)
logger.Error(report)
stat.Report(report)
if _, e := c.rds.Del(key); e != nil {
logx.Errorf("delete invalid cache, node: %s, key: %s, value: %s, error: %v",
if _, e := c.rds.DelCtx(ctx, key); e != nil {
logger.Errorf("delete invalid cache, node: %s, key: %s, value: %s, error: %v",
c.rds.Addr, key, data, e)
}
@@ -233,6 +266,6 @@ func (c cacheNode) processCache(key, data string, v interface{}) error {
return c.errNotFound
}
func (c cacheNode) setCacheWithNotFound(key string) error {
return c.rds.Setex(key, notFoundPlaceholder, int(c.aroundDuration(c.notFoundExpiry).Seconds()))
func (c cacheNode) setCacheWithNotFound(ctx context.Context, key string) error {
return c.rds.SetexCtx(ctx, key, notFoundPlaceholder, int(c.aroundDuration(c.notFoundExpiry).Seconds()))
}

83
core/stores/redis/hook.go Normal file
View File

@@ -0,0 +1,83 @@
package redis
import (
"context"
"strings"
"time"
red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/mapping"
"github.com/zeromicro/go-zero/core/timex"
)
var (
startTimeKey = contextKey("startTime")
durationHook = hook{}
)
type (
contextKey string
hook struct{}
)
func (h hook) BeforeProcess(ctx context.Context, _ red.Cmder) (context.Context, error) {
return context.WithValue(ctx, startTimeKey, timex.Now()), nil
}
func (h hook) AfterProcess(ctx context.Context, cmd red.Cmder) error {
val := ctx.Value(startTimeKey)
if val == nil {
return nil
}
start, ok := val.(time.Duration)
if !ok {
return nil
}
duration := timex.Since(start)
if duration > slowThreshold.Load() {
logDuration(ctx, cmd, duration)
}
return nil
}
func (h hook) BeforeProcessPipeline(ctx context.Context, _ []red.Cmder) (context.Context, error) {
return context.WithValue(ctx, startTimeKey, timex.Now()), nil
}
func (h hook) AfterProcessPipeline(ctx context.Context, cmds []red.Cmder) error {
if len(cmds) == 0 {
return nil
}
val := ctx.Value(startTimeKey)
if val == nil {
return nil
}
start, ok := val.(time.Duration)
if !ok {
return nil
}
duration := timex.Since(start)
if duration > slowThreshold.Load()*time.Duration(len(cmds)) {
logDuration(ctx, cmds[0], duration)
}
return nil
}
func logDuration(ctx context.Context, cmd red.Cmder, duration time.Duration) {
var buf strings.Builder
for i, arg := range cmd.Args() {
if i > 0 {
buf.WriteByte(' ')
}
buf.WriteString(mapping.Repr(arg))
}
logx.WithContext(ctx).WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
}

View File

@@ -0,0 +1,137 @@
package redis
import (
"context"
"log"
"strings"
"testing"
"time"
red "github.com/go-redis/redis/v8"
"github.com/stretchr/testify/assert"
)
func TestHookProcessCase1(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx, err := durationHook.BeforeProcess(context.Background(), nil)
if err != nil {
t.Fatal(err)
}
assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background())))
assert.False(t, strings.Contains(buf.String(), "slow"))
}
func TestHookProcessCase2(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx, err := durationHook.BeforeProcess(context.Background(), nil)
if err != nil {
t.Fatal(err)
}
time.Sleep(slowThreshold.Load() + time.Millisecond)
assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background(), "foo", "bar")))
assert.True(t, strings.Contains(buf.String(), "slow"))
}
func TestHookProcessCase3(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
assert.Nil(t, durationHook.AfterProcess(context.Background(), red.NewCmd(context.Background())))
assert.True(t, buf.Len() == 0)
}
func TestHookProcessCase4(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx := context.WithValue(context.Background(), startTimeKey, "foo")
assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background())))
assert.True(t, buf.Len() == 0)
}
func TestHookProcessPipelineCase1(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx, err := durationHook.BeforeProcessPipeline(context.Background(), nil)
if err != nil {
t.Fatal(err)
}
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
red.NewCmd(context.Background()),
}))
assert.False(t, strings.Contains(buf.String(), "slow"))
}
func TestHookProcessPipelineCase2(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx, err := durationHook.BeforeProcessPipeline(context.Background(), nil)
if err != nil {
t.Fatal(err)
}
time.Sleep(slowThreshold.Load() + time.Millisecond)
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
red.NewCmd(context.Background(), "foo", "bar"),
}))
assert.True(t, strings.Contains(buf.String(), "slow"))
}
func TestHookProcessPipelineCase3(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
assert.Nil(t, durationHook.AfterProcessPipeline(context.Background(), []red.Cmder{
red.NewCmd(context.Background()),
}))
assert.True(t, buf.Len() == 0)
}
func TestHookProcessPipelineCase4(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx := context.WithValue(context.Background(), startTimeKey, "foo")
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
red.NewCmd(context.Background()),
}))
assert.True(t, buf.Len() == 0)
}
func TestHookProcessPipelineCase5(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx := context.WithValue(context.Background(), startTimeKey, "foo")
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, nil))
assert.True(t, buf.Len() == 0)
}

View File

@@ -1,32 +0,0 @@
package redis
import (
"strings"
red "github.com/go-redis/redis"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/mapping"
"github.com/zeromicro/go-zero/core/timex"
)
func checkDuration(proc func(red.Cmder) error) func(red.Cmder) error {
return func(cmd red.Cmder) error {
start := timex.Now()
defer func() {
duration := timex.Since(start)
if duration > slowThreshold.Load() {
var buf strings.Builder
for i, arg := range cmd.Args() {
if i > 0 {
buf.WriteByte(' ')
}
buf.WriteString(mapping.Repr(arg))
}
logx.WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
}
}()
return proc(cmd)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
package redis
import (
"context"
"crypto/tls"
"errors"
"io"
@@ -9,8 +10,9 @@ import (
"time"
"github.com/alicebob/miniredis/v2"
red "github.com/go-redis/redis"
red "github.com/go-redis/redis/v8"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stringx"
)
@@ -963,13 +965,14 @@ func TestRedis_SortedSet(t *testing.T) {
assert.NotNil(t, err)
client.Zadd("second", 2, "aa")
client.Zadd("third", 3, "bbb")
val, err = client.Zunionstore("union", ZStore{
val, err = client.Zunionstore("union", &ZStore{
Keys: []string{"second", "third"},
Weights: []float64{1, 2},
Aggregate: "SUM",
}, "second", "third")
})
assert.Nil(t, err)
assert.Equal(t, int64(2), val)
_, err = New(client.Addr, badType()).Zunionstore("union", ZStore{})
_, err = New(client.Addr, badType()).Zunionstore("union", &ZStore{})
assert.NotNil(t, err)
vals, err = client.Zrange("union", 0, 10000)
assert.Nil(t, err)
@@ -987,9 +990,9 @@ func TestRedis_Pipelined(t *testing.T) {
}))
err := client.Pipelined(
func(pipe Pipeliner) error {
pipe.Incr("pipelined_counter")
pipe.Expire("pipelined_counter", time.Hour)
pipe.ZAdd("zadd", Z{Score: 12, Member: "zadd"})
pipe.Incr(context.Background(), "pipelined_counter")
pipe.Expire(context.Background(), "pipelined_counter", time.Hour)
pipe.ZAdd(context.Background(), "zadd", &Z{Score: 12, Member: "zadd"})
return nil
},
)
@@ -1135,6 +1138,8 @@ func TestRedis_WithPass(t *testing.T) {
}
func runOnRedis(t *testing.T, fn func(client *Redis)) {
logx.Disable()
s, err := miniredis.Run()
assert.Nil(t, err)
defer func() {
@@ -1153,6 +1158,8 @@ func runOnRedis(t *testing.T, fn func(client *Redis)) {
}
func runOnRedisTLS(t *testing.T, fn func(client *Redis)) {
logx.Disable()
s, err := miniredis.RunTLS(&tls.Config{
Certificates: make([]tls.Certificate, 1),
InsecureSkipVerify: true,
@@ -1182,6 +1189,6 @@ type mockedNode struct {
RedisNode
}
func (n mockedNode) BLPop(timeout time.Duration, keys ...string) *red.StringSliceCmd {
return red.NewStringSliceCmd("foo", "bar")
func (n mockedNode) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *red.StringSliceCmd {
return red.NewStringSliceCmd(context.Background(), "foo", "bar")
}

View File

@@ -3,7 +3,7 @@ package redis
import (
"fmt"
red "github.com/go-redis/redis"
red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/logx"
)

View File

@@ -4,7 +4,7 @@ import (
"crypto/tls"
"io"
red "github.com/go-redis/redis"
red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/syncx"
)
@@ -32,7 +32,8 @@ func getClient(r *Redis) (*red.Client, error) {
MinIdleConns: idleConns,
TLSConfig: tlsConfig,
})
store.WrapProcess(checkDuration)
store.AddHook(durationHook)
return store, nil
})
if err != nil {

View File

@@ -4,7 +4,7 @@ import (
"crypto/tls"
"io"
red "github.com/go-redis/redis"
red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/syncx"
)
@@ -25,7 +25,7 @@ func getCluster(r *Redis) (*red.ClusterClient, error) {
MinIdleConns: idleConns,
TLSConfig: tlsConfig,
})
store.WrapProcess(checkDuration)
store.AddHook(durationHook)
return store, nil
})

View File

@@ -5,7 +5,7 @@ import (
"sync/atomic"
"time"
red "github.com/go-redis/redis"
red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stringx"
)

View File

@@ -17,10 +17,12 @@ func CreateRedis() (r *redis.Redis, clean func(), err error) {
return redis.New(mr.Addr()), func() {
ch := make(chan lang.PlaceholderType)
go func() {
mr.Close()
close(ch)
}()
select {
case <-ch:
case <-time.After(time.Second):

View File

@@ -4,9 +4,12 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
)
func TestScriptCache(t *testing.T) {
logx.Disable()
cache := GetScriptCache()
cache.SetSha("foo", "bar")
cache.SetSha("bla", "blabla")

View File

@@ -7,6 +7,9 @@ import (
"github.com/zeromicro/go-zero/core/lang"
)
// errTimeout indicates a timeout.
var errTimeout = errors.New("timeout")
type (
// Ticker interface wraps the Chan and Stop methods.
Ticker interface {
@@ -70,7 +73,7 @@ func (ft *fakeTicker) Tick() {
func (ft *fakeTicker) Wait(d time.Duration) error {
select {
case <-time.After(d):
return errors.New("timeout")
return errTimeout
case <-ft.done:
return nil
}

10
go.mod
View File

@@ -7,7 +7,6 @@ require (
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/alicebob/miniredis/v2 v2.17.0
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang/mock v1.6.0
@@ -28,7 +27,7 @@ require (
go.uber.org/automaxprocs v1.4.0
go.uber.org/goleak v1.1.12
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11
google.golang.org/grpc v1.43.0
google.golang.org/grpc v1.44.0
google.golang.org/protobuf v1.27.1
gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/h2non/gock.v1 v1.1.2
@@ -42,10 +41,11 @@ require (
require (
github.com/fatih/color v1.10.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
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-20220114011407-0dd24b26b47d // indirect
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect
google.golang.org/genproto v0.0.0-20220112215332-a9c7c0acf9f2 // 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
k8s.io/klog/v2 v2.40.1 // indirect
)

37
go.sum
View File

@@ -37,7 +37,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=
@@ -60,10 +59,9 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
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 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
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=
@@ -73,7 +71,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=
@@ -87,6 +84,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=
@@ -100,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=
@@ -142,8 +140,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=
@@ -352,7 +350,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=
@@ -486,8 +483,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-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/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,10 +545,12 @@ 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/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
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/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=
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=
@@ -647,8 +646,8 @@ 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 h1:z+R4M/SuyaRsj1zu3WC+nIQyfSrSIpuDcY01/R3uCtg=
google.golang.org/genproto v0.0.0-20220112215332-a9c7c0acf9f2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
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/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=
@@ -660,10 +659,9 @@ 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 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
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=
@@ -719,7 +717,6 @@ k8s.io/client-go v0.20.12 h1:U75SxTC31BHT9i7CbX/hL4v+U1Wkzy/E1vt5ClDPp3I=
k8s.io/client-go v0.20.12/go.mod h1:NBJj6Evp73Xy/4v/O/RDRaH0+3JoxNfjRxkyRgrdbsA=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ=
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4=
k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=

View File

@@ -11,6 +11,8 @@
[![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)
> ***缩短从需求到上线的距离***
**注意为了满足开源基金会要求go-zero 从好未来tal-tech组织下迁移至中立的 GitHub 组织zeromicro**
## 0. go-zero 介绍
@@ -87,7 +89,7 @@ go-zero 是一个集成了各种工程实践的包含 web 和 rpc 框架,有
在项目目录下通过如下命令安装:
```shell
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/go-zero
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro/go-zero
```
## 5. Quick Start
@@ -104,10 +106,10 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
```shell
# Go 1.15 及之前版本
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/go-zero/tools/goctl@latest
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro/go-zero/tools/goctl@latest
# Go 1.16 及以后版本
GOPROXY=https://goproxy.cn/,direct go install github.com/tal-tech/go-zero/tools/goctl@latest
GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest
```
确保 goctl 可执行
@@ -232,12 +234,14 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
>46. 上海游族网络
>47. 深信服
>48. 中免日上科技互联有限公司
>48. ECLOUDVALLEY TECHNOLOGY (HK) LIMITED
>48. 馨科智(深圳)科技有限公司
>48. 成都松珀科技有限公司
>48. 亿景智联
>48. 上海扩博智能技术有限公司
>48. 一犀科技成都有限公司
>49. ECLOUDVALLEY TECHNOLOGY (HK) LIMITED
>50. 馨科智(深圳)科技有限公司
>51. 成都松珀科技有限公司
>52. 亿景智联
>53. 上海扩博智能技术有限公司
>54. 一犀科技成都有限公司
>55. 北京术杰科技有限公司
>56. 时代脉搏网络科技(云浮市)有限公司
如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。

View File

@@ -90,7 +90,7 @@ As below, go-zero protects the system with a couple of layers and mechanisms:
Run the following command under your project:
```shell
go get -u github.com/tal-tech/go-zero
go get -u github.com/zeromicro/go-zero
```
## 6. Quick Start
@@ -107,10 +107,10 @@ go get -u github.com/tal-tech/go-zero
```shell
# for Go 1.15 and earlier
GO111MODULE=on go get -u github.com/tal-tech/go-zero/tools/goctl@latest
GO111MODULE=on go get -u github.com/zeromicro/go-zero/tools/goctl@latest
# for Go 1.16 and later
go install github.com/tal-tech/go-zero/tools/goctl@latest
go install github.com/zeromicro/go-zero/tools/goctl@latest
```
make sure goctl is executable.

View File

@@ -8,15 +8,15 @@ import (
"text/template"
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
const apiTemplate = `
syntax = "v1"
info(
info (
title: // TODO: add title
desc: // TODO: add description
author: "{{.gitUser}}"

View File

@@ -3,8 +3,8 @@ package apigen
import (
"fmt"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
const (

View File

@@ -4,9 +4,9 @@ import (
"errors"
"strings"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
)
// DartCommand create dart network request code

View File

@@ -4,7 +4,7 @@ import (
"os"
"text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
)
const apiTemplate = `import 'api.dart';

View File

@@ -4,7 +4,7 @@ import (
"os"
"text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
)
const dataTemplate = `// --{{with .Info}}{{.Title}}{{end}}--

View File

@@ -6,8 +6,8 @@ import (
"os"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/api/util"
)
func lowCamelCase(s string) string {

View File

@@ -7,10 +7,10 @@ import (
"strconv"
"strings"
"github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/api/gogen"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/api/util"
)
const (

View File

@@ -7,9 +7,9 @@ import (
"path/filepath"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
// DocCommand generate markdown doc file

View File

@@ -11,11 +11,11 @@ import (
"path/filepath"
"strings"
"github.com/tal-tech/go-zero/core/errorx"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/core/errorx"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
"github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
const (

View File

@@ -39,5 +39,5 @@ service A-api {
func TestFormat(t *testing.T) {
r, err := apiFormat(notFormattedStr)
assert.Nil(t, err)
assert.Equal(t, r, formattedStr)
assert.Equal(t, formattedStr, r)
}

View File

@@ -12,14 +12,14 @@ import (
"time"
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/core/logx"
apiformat "github.com/tal-tech/go-zero/tools/goctl/api/format"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/core/logx"
apiformat "github.com/zeromicro/go-zero/tools/goctl/api/format"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
const tmpFile = "%s-%d"

View File

@@ -9,7 +9,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
)
const testApiTemplate = `

View File

@@ -4,10 +4,10 @@ import (
"fmt"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/vars"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/zeromicro/go-zero/tools/goctl/vars"
)
const (

View File

@@ -4,9 +4,9 @@ import (
"fmt"
"strconv"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util/format"
)
const (

View File

@@ -5,13 +5,13 @@ import (
"path"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/internal/version"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/internal/version"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/vars"
)
const (

View File

@@ -6,12 +6,12 @@ import (
"strconv"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/vars"
)
const logicTemplate = `package {{.pkgName}}

View File

@@ -4,11 +4,11 @@ import (
"fmt"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/vars"
)
const mainTemplate = `package main

View File

@@ -3,9 +3,9 @@ package gogen
import (
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util/format"
)
var middlewareImplementCode = `

View File

@@ -8,12 +8,12 @@ import (
"strings"
"text/template"
"github.com/tal-tech/go-zero/core/collection"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars"
"github.com/zeromicro/go-zero/core/collection"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/vars"
)
const (

View File

@@ -4,11 +4,11 @@ import (
"fmt"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/vars"
)
const (

View File

@@ -7,11 +7,11 @@ import (
"path"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/format"
)
const (

View File

@@ -3,8 +3,8 @@ package gogen
import (
"fmt"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
const (

View File

@@ -6,7 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
func TestGenTemplates(t *testing.T) {

View File

@@ -9,11 +9,11 @@ import (
"strings"
"text/template"
"github.com/tal-tech/go-zero/core/collection"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/core/collection"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/util/ctx"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
type fileGenConfig struct {

View File

@@ -6,10 +6,10 @@ import (
"strings"
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
// JavaCommand the generate java code command entrance

View File

@@ -10,11 +10,11 @@ import (
"strings"
"text/template"
"github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
const (

View File

@@ -6,10 +6,10 @@ import (
"strings"
"text/template"
"github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/util"
)
const packetTemplate = `package com.xhb.logic.http.packet.{{.packet}};

View File

@@ -6,9 +6,9 @@ import (
"io"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
func writeProperty(writer io.Writer, member spec.Member, indent int) error {

View File

@@ -3,8 +3,8 @@ package ktgen
import (
"errors"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
)
// KtCommand the generate kotlin code command entrance

View File

@@ -7,7 +7,7 @@ import (
"text/template"
"github.com/iancoleman/strcase"
"github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/api/util"
)
var funcsMap = template.FuncMap{

View File

@@ -7,7 +7,7 @@ import (
"text/template"
"github.com/iancoleman/strcase"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
)
const (

View File

@@ -7,11 +7,11 @@ import (
"strings"
"text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/gogen"
conf "github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
conf "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
const apiTemplate = `

View File

@@ -3,8 +3,8 @@ package new
import (
"fmt"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
const (

View File

@@ -5,7 +5,7 @@ import (
"path"
"sort"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
const prefixKey = "prefix"

View File

@@ -7,9 +7,9 @@ import (
"path/filepath"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/tal-tech/go-zero/tools/goctl/util/console"
"github.com/zeromicro/antlr"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/util/console"
)
type (

View File

@@ -5,9 +5,9 @@ import (
"sort"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/tal-tech/go-zero/tools/goctl/util/console"
"github.com/zeromicro/antlr"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/util/console"
)
type (

View File

@@ -1,7 +1,7 @@
package ast
import (
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
// ImportExpr defines import syntax for api

View File

@@ -1,7 +1,7 @@
package ast
import (
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
// InfoExpr defines info syntax for api

View File

@@ -3,7 +3,7 @@ package ast
import (
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
// KvExpr describes key-value for api

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"sort"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
// Service describes service for api syntax

View File

@@ -1,7 +1,7 @@
package ast
import (
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
// SyntaxExpr describes syntax for api

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"sort"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
type (

View File

@@ -634,4 +634,3 @@ func NewSyntaxLitContext(parser antlr.Parser, parent antlr.ParserRuleContext, in
return p
}

View File

@@ -8,8 +8,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
var (

View File

@@ -5,8 +5,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
var parser = ast.NewParser(ast.WithParserPrefix("test.api"), ast.WithParserDebug())

View File

@@ -5,8 +5,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
var importAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {

View File

@@ -4,8 +4,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
var infoAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {

View File

@@ -4,8 +4,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
func TestBody(t *testing.T) {

View File

@@ -4,8 +4,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
var syntaxAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {

View File

@@ -4,8 +4,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
)
var fieldAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {

View File

@@ -5,9 +5,9 @@ import (
"path/filepath"
"unicode"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
)
type parser struct {

View File

@@ -4,7 +4,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
)
var testApi = "// syntax doc\nsyntax = \"v1\" // syntax comment\n\n// type doc\ntype Request {\n\tName string `path:\"name,options=you|me\"`\n}\n\ntype Response {\n\tMessage string `json:\"message\"`\n}\n\n// service doc\nservice greet-api {\n\t// handler doc\n\t@handler GreetHandler // handler comment\n\tget /from/:name(Request) returns (Response);\n}"

View File

@@ -5,8 +5,8 @@ import (
"path"
"strings"
"github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/zeromicro/go-zero/tools/goctl/util"
)
const (

View File

@@ -5,10 +5,10 @@ import (
"fmt"
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
// TsCommand provides the entry to generate typescript codes

View File

@@ -5,9 +5,9 @@ import (
"strings"
"text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
const (

View File

@@ -6,10 +6,10 @@ import (
"strings"
"text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
const (

View File

@@ -6,9 +6,9 @@ import (
"io"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/util"
)
func writeProperty(writer io.Writer, member spec.Member, indent int) error {

View File

@@ -8,9 +8,9 @@ import (
"path"
"strings"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
// MaybeCreateFile creates file if not exists

View File

@@ -5,8 +5,8 @@ import (
"fmt"
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
)
// GoValidateApi verifies whether the api has a syntax error

View File

@@ -6,8 +6,8 @@ import (
"os/exec"
"runtime"
"github.com/tal-tech/go-zero/tools/goctl/internal/version"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/internal/version"
)
const (

View File

@@ -6,7 +6,7 @@ import (
"runtime"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/internal/version"
"github.com/zeromicro/go-zero/tools/goctl/internal/version"
)
type env map[string]string

View File

@@ -0,0 +1,79 @@
package completion
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"github.com/logrusorgru/aurora"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/vars"
)
func Completion(c *cli.Context) error {
goos := runtime.GOOS
if goos == vars.OsWindows {
return fmt.Errorf("%q: only support unix-like OS", goos)
}
name := c.String("name")
if len(name) == 0 {
name = defaultCompletionFilename
}
if filepath.IsAbs(name) {
return fmt.Errorf("unsupport absolute path: %q", name)
}
home, err := pathx.GetAutoCompleteHome()
if err != nil {
return err
}
buffer := bytes.NewBuffer(nil)
zshF := filepath.Join(home, "zsh", defaultCompletionFilename)
err = pathx.MkdirIfNotExist(filepath.Dir(zshF))
if err != nil {
return err
}
bashF := filepath.Join(home, "bash", defaultCompletionFilename)
err = pathx.MkdirIfNotExist(filepath.Dir(bashF))
if err != nil {
return err
}
flag := magic
err = ioutil.WriteFile(zshF, zsh, os.ModePerm)
if err != nil {
return err
}
flag |= flagZsh
err = ioutil.WriteFile(bashF, bash, os.ModePerm)
if err != nil {
return err
}
flag |= flagBash
buffer.WriteString(aurora.BrightGreen("generation auto completion success!\n").String())
buffer.WriteString(aurora.BrightGreen("executes the following script to setting shell:\n").String())
switch flag {
case magic | flagZsh:
buffer.WriteString(aurora.BrightCyan(fmt.Sprintf("echo PROG=goctl source %s >> ~/.zshrc && source ~/.zshrc", zshF)).String())
case magic | flagBash:
buffer.WriteString(aurora.BrightCyan(fmt.Sprintf("echo PROG=goctl source %s >> ~/.bashrc && source ~/.bashrc", bashF)).String())
case magic | flagZsh | flagBash:
buffer.WriteString(aurora.BrightCyan(fmt.Sprintf(`echo PROG=goctl source %s >> ~/.zshrc && source ~/.zshrc
or
echo PROG=goctl source %s >> ~/.bashrc && source ~/.bashrc`, zshF, bashF)).String())
default:
return nil
}
fmt.Println(buffer.String())
return nil
}

View File

@@ -0,0 +1,9 @@
package completion
const BashCompletionFlag = `generate-goctl-completion`
const defaultCompletionFilename = "goctl_autocomplete"
const (
magic = 1 << iota
flagZsh
flagBash
)

View File

@@ -0,0 +1,51 @@
package completion
import "fmt"
var zsh = []byte(fmt.Sprintf(`#compdef $PROG
_cli_zsh_autocomplete() {
local -a opts
local cur
cur=${words[-1]}
if [[ "$cur" == "-"* ]]; then
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --%s)}")
else
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --%s)}")
fi
if [[ "${opts[1]}" != "" ]]; then
_describe 'values' opts
else
_files
fi
return
}
compdef _cli_zsh_autocomplete $PROG
`, BashCompletionFlag, BashCompletionFlag))
var bash = []byte(fmt.Sprintf(`#! /bin/bash
: ${PROG:=$(basename ${BASH_SOURCE})}
_cli_bash_autocomplete() {
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
local cur opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ "$cur" == "-"* ]]; then
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --%s )
else
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --%s )
fi
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
}
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete $PROG
unset PROG
`, BashCompletionFlag, BashCompletionFlag))

Some files were not shown because too many files have changed in this diff Show More