Commit 28bc9099 by Joneq

ready

parents
.idea
*.properties
*.iml
/logs
.DS_Store?
.DS_Store
/configs
/sh
go.sum
\ No newline at end of file
## Demo
### v1.0.0
1. 上线功能xxx
# Author
# Reviewer
# Demo
## 项目简介
1.
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: api.proto
/*
Package api is a generated blademaster stub package.
This code was generated with kratos/tool/protobuf/protoc-gen-bm v0.1.
package 命名使用 {appid}.{version} 的方式, version 形如 v1, v2 ..
It is generated from these files:
api.proto
*/
package api
import (
"context"
bm "github.com/go-kratos/kratos/pkg/net/http/blademaster"
"github.com/go-kratos/kratos/pkg/net/http/blademaster/binding"
)
import google_protobuf1 "github.com/golang/protobuf/ptypes/empty"
// to suppressed 'imported but not used warning'
var _ *bm.Context
var _ context.Context
var _ binding.StructValidator
var PathDemoPing = "/demo.service.v1.Demo/Ping"
var PathDemoSayHello = "/demo.service.v1.Demo/SayHello"
var PathDemoSayHelloURL = "/kratos-demo/say_hello"
// DemoBMServer is the server API for Demo service.
type DemoBMServer interface {
Ping(ctx context.Context, req *google_protobuf1.Empty) (resp *google_protobuf1.Empty, err error)
SayHello(ctx context.Context, req *HelloReq) (resp *google_protobuf1.Empty, err error)
SayHelloURL(ctx context.Context, req *HelloReq) (resp *HelloResp, err error)
}
var DemoSvc DemoBMServer
func demoPing(c *bm.Context) {
p := new(google_protobuf1.Empty)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := DemoSvc.Ping(c, p)
c.JSON(resp, err)
}
func demoSayHello(c *bm.Context) {
p := new(HelloReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := DemoSvc.SayHello(c, p)
c.JSON(resp, err)
}
func demoSayHelloURL(c *bm.Context) {
p := new(HelloReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := DemoSvc.SayHelloURL(c, p)
c.JSON(resp, err)
}
// RegisterDemoBMServer Register the blademaster route
func RegisterDemoBMServer(e *bm.Engine, server DemoBMServer) {
DemoSvc = server
e.GET("/demo.service.v1.Demo/Ping", demoPing)
e.GET("/demo.service.v1.Demo/SayHello", demoSayHello)
e.GET("/kratos-demo/say_hello", demoSayHelloURL)
}
// 定义项目 API 的 proto 文件 可以同时描述 gRPC 和 HTTP API
// protobuf 文件参考:
// - https://developers.google.com/protocol-buffers/
syntax = "proto3";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "google/protobuf/empty.proto";
import "google/api/annotations.proto";
// package 命名使用 {appid}.{version} 的方式, version 形如 v1, v2 ..
package demo.service.v1;
// NOTE: 最后请删除这些无用的注释 (゜-゜)つロ
option go_package = "api";
option (gogoproto.goproto_getters_all) = false;
service Demo {
rpc Ping(.google.protobuf.Empty) returns (.google.protobuf.Empty);
rpc SayHello(HelloReq) returns (.google.protobuf.Empty);
rpc SayHelloURL(HelloReq) returns (HelloResp) {
option (google.api.http) = {
get: "/kratos-demo/say_hello"
};
};
}
message HelloReq {
string name = 1 [(gogoproto.moretags) = 'form:"name" validate:"required"'];
}
message HelloResp {
string Content = 1 [(gogoproto.jsontag) = 'content'];
}
package api
import (
"context"
"fmt"
"github.com/go-kratos/kratos/pkg/net/rpc/warden"
"google.golang.org/grpc"
)
// AppID .
const AppID = "TODO: ADD APP ID"
// NewClient new grpc client
func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (DemoClient, error) {
client := warden.NewClient(cfg, opts...)
cc, err := client.Dial(context.Background(), fmt.Sprintf("discovery://default/%s", AppID))
if err != nil {
return nil, err
}
return NewDemoClient(cc), nil
}
// 生成 gRPC 代码
//go:generate kratos tool protoc --grpc --bm api.proto
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"photo_taking/internal/di"
"github.com/go-kratos/kratos/pkg/conf/paladin"
"github.com/go-kratos/kratos/pkg/log"
)
func main() {
flag.Parse()
log.Init(nil) // debug flag: log.dir={path}
defer log.Close()
log.Info("photo_taking start")
paladin.Init()
_, closeFunc, err := di.InitApp()
if err != nil {
panic(err)
}
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
closeFunc()
log.Info("photo_taking exit")
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}
module photo_taking
go 1.13
require (
github.com/go-kratos/kratos v0.5.1-0.20200526160825-521d240568d0
github.com/gogo/protobuf v1.3.1
github.com/golang/protobuf v1.3.5
github.com/google/wire v0.4.0
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
google.golang.org/genproto v0.0.0-20200402124713-8ff61da6d932
google.golang.org/grpc v1.28.1
)
// Code generated by kratos tool genbts. DO NOT EDIT.
/*
Package dao is a generated cache proxy package.
It is generated from:
type Dao interface {
Close()
Ping(ctx context.Context) (err error)
// bts: -nullcache=&model.Article{ID:-1} -check_null_code=$!=nil&&$.ID==-1
Article(c context.Context, id int64) (*model.Article, error)
}
*/
package dao
import (
"context"
"github.com/go-kratos/kratos/pkg/cache"
"photo_taking/internal/model"
)
// Article get data from cache if miss will call source method, then add to cache.
func (d *dao) Article(c context.Context, id int64) (res *model.Article, err error) {
addCache := true
res, err = d.CacheArticle(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res != nil && res.ID == -1 {
res = nil
}
}()
if res != nil {
cache.MetricHits.Inc("bts:Article")
return
}
cache.MetricMisses.Inc("bts:Article")
res, err = d.RawArticle(c, id)
if err != nil {
return
}
miss := res
if miss == nil {
miss = &model.Article{ID: -1}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheArticle(c, id, miss)
})
return
}
package dao
import (
"context"
"time"
"photo_taking/internal/model"
"github.com/go-kratos/kratos/pkg/cache/memcache"
"github.com/go-kratos/kratos/pkg/cache/redis"
"github.com/go-kratos/kratos/pkg/conf/paladin"
"github.com/go-kratos/kratos/pkg/database/sql"
"github.com/go-kratos/kratos/pkg/sync/pipeline/fanout"
xtime "github.com/go-kratos/kratos/pkg/time"
"github.com/google/wire"
)
var Provider = wire.NewSet(New, NewDB, NewRedis, NewMC)
//go:generate kratos tool genbts
// Dao dao interface
type Dao interface {
Close()
Ping(ctx context.Context) (err error)
// bts: -nullcache=&model.Article{ID:-1} -check_null_code=$!=nil&&$.ID==-1
Article(c context.Context, id int64) (*model.Article, error)
}
// dao dao.
type dao struct {
db *sql.DB
redis *redis.Redis
mc *memcache.Memcache
cache *fanout.Fanout
demoExpire int32
}
// New new a dao and return.
func New(r *redis.Redis, mc *memcache.Memcache, db *sql.DB) (d Dao, cf func(), err error) {
return newDao(r, mc, db)
}
func newDao(r *redis.Redis, mc *memcache.Memcache, db *sql.DB) (d *dao, cf func(), err error) {
var cfg struct{
DemoExpire xtime.Duration
}
if err = paladin.Get("application.toml").UnmarshalTOML(&cfg); err != nil {
return
}
d = &dao{
db: db,
redis: r,
mc: mc,
cache: fanout.New("cache"),
demoExpire: int32(time.Duration(cfg.DemoExpire) / time.Second),
}
cf = d.Close
return
}
// Close close the resource.
func (d *dao) Close() {
d.cache.Close()
}
// Ping ping the resource.
func (d *dao) Ping(ctx context.Context) (err error) {
return nil
}
package dao
import (
"context"
"flag"
"os"
"testing"
"github.com/go-kratos/kratos/pkg/conf/paladin"
"github.com/go-kratos/kratos/pkg/testing/lich"
)
var d *dao
var ctx = context.Background()
func TestMain(m *testing.M) {
flag.Set("conf", "../../test")
flag.Set("f", "../../test/docker-compose.yaml")
flag.Parse()
disableLich := os.Getenv("DISABLE_LICH") != ""
if !disableLich {
if err := lich.Setup(); err != nil {
panic(err)
}
}
var err error
if err = paladin.Init(); err != nil {
panic(err)
}
var cf func()
if d, cf, err = newTestDao();err != nil {
panic(err)
}
ret := m.Run()
cf()
if !disableLich {
_ = lich.Teardown()
}
os.Exit(ret)
}
package dao
import (
"context"
"photo_taking/internal/model"
"github.com/go-kratos/kratos/pkg/conf/paladin"
"github.com/go-kratos/kratos/pkg/database/sql"
)
func NewDB() (db *sql.DB, cf func(), err error) {
var (
cfg sql.Config
ct paladin.TOML
)
if err = paladin.Get("db.toml").Unmarshal(&ct); err != nil {
return
}
if err = ct.Get("Client").UnmarshalTOML(&cfg); err != nil {
return
}
db = sql.NewMySQL(&cfg)
cf = func() {db.Close()}
return
}
func (d *dao) RawArticle(ctx context.Context, id int64) (art *model.Article, err error) {
// get data from db
return
}
// Code generated by kratos tool genmc. DO NOT EDIT.
/*
Package dao is a generated mc cache package.
It is generated from:
type _mc interface {
// mc: -key=keyArt -type=get
CacheArticle(c context.Context, id int64) (*model.Article, error)
// mc: -key=keyArt -expire=d.demoExpire
AddCacheArticle(c context.Context, id int64, art *model.Article) (err error)
// mc: -key=keyArt
DeleteArticleCache(c context.Context, id int64) (err error)
}
*/
package dao
import (
"context"
"fmt"
"github.com/go-kratos/kratos/pkg/cache/memcache"
"github.com/go-kratos/kratos/pkg/log"
"photo_taking/internal/model"
)
var _ _mc
// CacheArticle get data from mc
func (d *dao) CacheArticle(c context.Context, id int64) (res *model.Article, err error) {
key := keyArt(id)
res = &model.Article{}
if err = d.mc.Get(c, key).Scan(res); err != nil {
res = nil
if err == memcache.ErrNotFound {
err = nil
}
}
if err != nil {
log.Errorv(c, log.KV("CacheArticle", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheArticle Set data to mc
func (d *dao) AddCacheArticle(c context.Context, id int64, val *model.Article) (err error) {
if val == nil {
return
}
key := keyArt(id)
item := &memcache.Item{Key: key, Object: val, Expiration: d.demoExpire, Flags: memcache.FlagJSON}
if err = d.mc.Set(c, item); err != nil {
log.Errorv(c, log.KV("AddCacheArticle", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DeleteArticleCache delete data from mc
func (d *dao) DeleteArticleCache(c context.Context, id int64) (err error) {
key := keyArt(id)
if err = d.mc.Delete(c, key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Errorv(c, log.KV("DeleteArticleCache", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
package dao
import (
"context"
"fmt"
"photo_taking/internal/model"
"github.com/go-kratos/kratos/pkg/cache/memcache"
"github.com/go-kratos/kratos/pkg/conf/paladin"
"github.com/go-kratos/kratos/pkg/log"
)
//go:generate kratos tool genmc
type _mc interface {
// mc: -key=keyArt -type=get
CacheArticle(c context.Context, id int64) (*model.Article, error)
// mc: -key=keyArt -expire=d.demoExpire
AddCacheArticle(c context.Context, id int64, art *model.Article) (err error)
// mc: -key=keyArt
DeleteArticleCache(c context.Context, id int64) (err error)
}
func NewMC() (mc *memcache.Memcache, cf func(), err error) {
var (
cfg memcache.Config
ct paladin.TOML
)
if err = paladin.Get("memcache.toml").Unmarshal(&ct); err != nil {
return
}
if err = ct.Get("Client").UnmarshalTOML(&cfg); err != nil {
return
}
mc = memcache.New(&cfg)
cf = func() {mc.Close()}
return
}
func (d *dao) PingMC(ctx context.Context) (err error) {
if err = d.mc.Set(ctx, &memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}); err != nil {
log.Error("conn.Set(PING) error(%v)", err)
}
return
}
func keyArt(id int64) string {
return fmt.Sprintf("art_%d", id)
}
package dao
import (
"context"
"github.com/go-kratos/kratos/pkg/cache/redis"
"github.com/go-kratos/kratos/pkg/conf/paladin"
"github.com/go-kratos/kratos/pkg/log"
)
func NewRedis() (r *redis.Redis, cf func(), err error) {
var (
cfg redis.Config
ct paladin.Map
)
if err = paladin.Get("redis.toml").Unmarshal(&ct); err != nil {
return
}
if err = ct.Get("Client").UnmarshalTOML(&cfg); err != nil {
return
}
r = redis.NewRedis(&cfg)
cf = func(){r.Close()}
return
}
func (d *dao) PingRedis(ctx context.Context) (err error) {
if _, err = d.redis.Do(ctx, "SET", "ping", "pong"); err != nil {
log.Error("conn.Set(PING) error(%v)", err)
}
return
}
\ No newline at end of file
// +build wireinject
// The build tag makes sure the stub is not built in the final build.
package dao
import (
"github.com/google/wire"
)
//go:generate kratos tool wire
func newTestDao() (*dao, func(), error) {
panic(wire.Build(newDao, NewDB, NewRedis, NewMC))
}
// Code generated by Wire. DO NOT EDIT.
//go:generate wire
//+build !wireinject
package dao
// Injectors from wire.go:
func newTestDao() (*dao, func(), error) {
redis, cleanup, err := NewRedis()
if err != nil {
return nil, nil, err
}
memcache, cleanup2, err := NewMC()
if err != nil {
cleanup()
return nil, nil, err
}
db, cleanup3, err := NewDB()
if err != nil {
cleanup2()
cleanup()
return nil, nil, err
}
daoDao, cleanup4, err := newDao(redis, memcache, db)
if err != nil {
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
return daoDao, func() {
cleanup4()
cleanup3()
cleanup2()
cleanup()
}, nil
}
package di
import (
"context"
"time"
"photo_taking/internal/service"
"github.com/go-kratos/kratos/pkg/log"
bm "github.com/go-kratos/kratos/pkg/net/http/blademaster"
"github.com/go-kratos/kratos/pkg/net/rpc/warden"
)
//go:generate kratos tool wire
type App struct {
svc *service.Service
http *bm.Engine
grpc *warden.Server
}
func NewApp(svc *service.Service, h *bm.Engine, g *warden.Server) (app *App, closeFunc func(), err error){
app = &App{
svc: svc,
http: h,
grpc: g,
}
closeFunc = func() {
ctx, cancel := context.WithTimeout(context.Background(), 35*time.Second)
if err := g.Shutdown(ctx); err != nil {
log.Error("grpcSrv.Shutdown error(%v)", err)
}
if err := h.Shutdown(ctx); err != nil {
log.Error("httpSrv.Shutdown error(%v)", err)
}
cancel()
}
return
}
// +build wireinject
// The build tag makes sure the stub is not built in the final build.
package di
import (
"photo_taking/internal/dao"
"photo_taking/internal/service"
"photo_taking/internal/server/grpc"
"photo_taking/internal/server/http"
"github.com/google/wire"
)
//go:generate kratos t wire
func InitApp() (*App, func(), error) {
panic(wire.Build(dao.Provider, service.Provider, http.New, grpc.New, NewApp))
}
// Code generated by Wire. DO NOT EDIT.
//go:generate wire
//+build !wireinject
package di
import (
"photo_taking/internal/dao"
"photo_taking/internal/server/grpc"
"photo_taking/internal/server/http"
"photo_taking/internal/service"
)
// Injectors from wire.go:
func InitApp() (*App, func(), error) {
redis, cleanup, err := dao.NewRedis()
if err != nil {
return nil, nil, err
}
memcache, cleanup2, err := dao.NewMC()
if err != nil {
cleanup()
return nil, nil, err
}
db, cleanup3, err := dao.NewDB()
if err != nil {
cleanup2()
cleanup()
return nil, nil, err
}
daoDao, cleanup4, err := dao.New(redis, memcache, db)
if err != nil {
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
serviceService, cleanup5, err := service.New(daoDao)
if err != nil {
cleanup4()
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
engine, err := http.New(serviceService)
if err != nil {
cleanup5()
cleanup4()
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
server, err := grpc.New(serviceService)
if err != nil {
cleanup5()
cleanup4()
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
app, cleanup6, err := NewApp(serviceService, engine, server)
if err != nil {
cleanup5()
cleanup4()
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
return app, func() {
cleanup6()
cleanup5()
cleanup4()
cleanup3()
cleanup2()
cleanup()
}, nil
}
package model
// Kratos hello kratos.
type Kratos struct {
Hello string
}
type Article struct {
ID int64
Content string
Author string
}
\ No newline at end of file
package grpc
import (
pb "photo_taking/api"
"github.com/go-kratos/kratos/pkg/conf/paladin"
"github.com/go-kratos/kratos/pkg/net/rpc/warden"
)
// New new a grpc server.
func New(svc pb.DemoServer) (ws *warden.Server, err error) {
var (
cfg warden.ServerConfig
ct paladin.TOML
)
if err = paladin.Get("grpc.toml").Unmarshal(&ct); err != nil {
return
}
if err = ct.Get("Server").UnmarshalTOML(&cfg); err != nil {
return
}
ws = warden.NewServer(&cfg)
pb.RegisterDemoServer(ws.Server(), svc)
ws, err = ws.Start()
return
}
package http
import (
"net/http"
pb "photo_taking/api"
"photo_taking/internal/model"
"github.com/go-kratos/kratos/pkg/conf/paladin"
"github.com/go-kratos/kratos/pkg/log"
bm "github.com/go-kratos/kratos/pkg/net/http/blademaster"
)
var svc pb.DemoServer
// New new a bm server.
func New(s pb.DemoServer) (engine *bm.Engine, err error) {
var (
cfg bm.ServerConfig
ct paladin.TOML
)
if err = paladin.Get("http.toml").Unmarshal(&ct); err != nil {
return
}
if err = ct.Get("Server").UnmarshalTOML(&cfg); err != nil {
return
}
svc = s
engine = bm.DefaultServer(&cfg)
pb.RegisterDemoBMServer(engine, s)
initRouter(engine)
err = engine.Start()
return
}
func initRouter(e *bm.Engine) {
e.Ping(ping)
g := e.Group("/photo_taking")
{
g.GET("/start", howToStart)
}
}
func ping(ctx *bm.Context) {
if _, err := svc.Ping(ctx, nil); err != nil {
log.Error("ping error(%v)", err)
ctx.AbortWithStatus(http.StatusServiceUnavailable)
}
}
// example for http request handler.
func howToStart(c *bm.Context) {
k := &model.Kratos{
Hello: "Golang 大法好 !!!",
}
c.JSON(k, nil)
}
\ No newline at end of file
package service
import (
"context"
"fmt"
pb "photo_taking/api"
"photo_taking/internal/dao"
"github.com/go-kratos/kratos/pkg/conf/paladin"
"github.com/golang/protobuf/ptypes/empty"
"github.com/google/wire"
)
var Provider = wire.NewSet(New, wire.Bind(new(pb.DemoServer), new(*Service)))
// Service service.
type Service struct {
ac *paladin.Map
dao dao.Dao
}
// New new a service and return.
func New(d dao.Dao) (s *Service, cf func(), err error) {
s = &Service{
ac: &paladin.TOML{},
dao: d,
}
cf = s.Close
err = paladin.Watch("application.toml", s.ac)
return
}
// SayHello grpc demo func.
func (s *Service) SayHello(ctx context.Context, req *pb.HelloReq) (reply *empty.Empty, err error) {
reply = new(empty.Empty)
fmt.Printf("hello %s", req.Name)
return
}
// SayHelloURL bm demo func.
func (s *Service) SayHelloURL(ctx context.Context, req *pb.HelloReq) (reply *pb.HelloResp, err error) {
reply = &pb.HelloResp{
Content: "hello " + req.Name,
}
fmt.Printf("hello url %s", req.Name)
return
}
// Ping ping the resource.
func (s *Service) Ping(ctx context.Context, e *empty.Empty) (*empty.Empty, error) {
return &empty.Empty{}, s.dao.Ping(ctx)
}
// Close close the resource.
func (s *Service) Close() {
}
create database kratos_demo;
use kratos_demo;
CREATE TABLE `articles` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`title` varchar(64) NOT NULL COMMENT '名称',
`mtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
`ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `ix_mtime` (`mtime`)
) COMMENT='文章表';
use kratos_demo;
INSERT INTO articles(`id`, `title`) VALUES (1, 'title');
# This is a TOML document. Boom~
demoExpire = "24h"
[Client]
dsn = "root:root@tcp(127.0.0.1:13306)/kratos_demo?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8"
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "200ms"
execTimeout = "300ms"
tranTimeout = "400ms"
version: "3.7"
services:
db:
image: mysql:5.6
ports:
- 13306:3306
environment:
- MYSQL_ROOT_PASSWORD=root
- TZ=Asia/Shanghai
volumes:
- .:/docker-entrypoint-initdb.d
command: [
'--character-set-server=utf8',
'--collation-server=utf8_unicode_ci'
]
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "--protocol=tcp"]
timeout: 20s
interval: 1s
retries: 20
redis:
image: redis
ports:
- 16379:6379
healthcheck:
test: ["CMD", "redis-cli","ping"]
interval: 20s
timeout: 1s
retries: 20
memcached:
image: memcached
ports:
- 21211:11211
healthcheck:
test: ["CMD", "echo", "stats", "|", "nc", "127.0.0.1", "11211"]
interval: 20s
timeout: 1s
retries: 20
[Server]
addr = "0.0.0.0:9000"
timeout = "1s"
[Server]
addr = "0.0.0.0:8000"
timeout = "1s"
[Client]
name = "demo"
proto = "tcp"
addr = "127.0.0.1:21211"
active = 50
idle = 10
dialTimeout = "100ms"
readTimeout = "200ms"
writeTimeout = "300ms"
idleTimeout = "80s"
[Client]
name = "demo"
proto = "tcp"
addr = "127.0.0.1:16379"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment