Skip to content

Commit

Permalink
gRPC去掉连接池, 设置keepAlive
Browse files Browse the repository at this point in the history
  • Loading branch information
ouqiang committed Jun 2, 2019
1 parent 0998599 commit c997ce7
Show file tree
Hide file tree
Showing 14 changed files with 138 additions and 412 deletions.
2 changes: 1 addition & 1 deletion internal/models/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type Host struct {
Id int16 `json:"id" xorm:"smallint pk autoincr"`
Name string `json:"name" xorm:"varchar(64) notnull"` // 主机名称
Alias string `json:"alias" xorm:"varchar(32) notnull default '' "` // 主机别名
Port int `json:"port" xorm:"notnull default 22"` // 主机端口
Port int `json:"port" xorm:"notnull default 5921"` // 主机端口
Remark string `json:"remark" xorm:"varchar(100) notnull default '' "` // 备注
BaseModel `json:"-" xorm:"-"`
Selected bool `json:"-" xorm:"-"`
Expand Down
2 changes: 1 addition & 1 deletion internal/models/task_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type TaskLog struct {
StartTime time.Time `json:"start_time" xorm:"datetime created"` // 开始执行时间
EndTime time.Time `json:"end_time" xorm:"datetime updated"` // 执行完成(失败)时间
Status Status `json:"status" xorm:"tinyint notnull index default 1"` // 状态 0:执行失败 1:执行中 2:执行完毕 3:任务取消(上次任务未执行完成) 4:异步执行
Result string `json:"result" xorm:"mediumtext notnull default '' "` // 执行结果
Result string `json:"result" xorm:"mediumtext notnull "` // 执行结果
TotalTime int `json:"total_time" xorm:"-"` // 执行总时长
BaseModel `json:"-" xorm:"-"`
}
Expand Down
20 changes: 7 additions & 13 deletions internal/modules/rpc/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,24 @@ func Exec(ip string, port int, taskReq *pb.TaskRequest) (string, error) {
}
}()
addr := fmt.Sprintf("%s:%d", ip, port)
conn, err := grpcpool.Pool.Get(addr)
c, err := grpcpool.Pool.Get(addr)
if err != nil {
return "", err
}
isConnClosed := false
defer func() {
if !isConnClosed {
grpcpool.Pool.Put(addr, conn)
}
}()
c := pb.NewTaskClient(conn)
if taskReq.Timeout <= 0 || taskReq.Timeout > 86400 {
taskReq.Timeout = 86400
}
timeout := time.Duration(taskReq.Timeout) * time.Second
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()

taskUniqueKey := generateTaskUniqueKey(ip, port, taskReq.Id)
taskMap.Store(taskUniqueKey, cancel)
defer taskMap.Delete(taskUniqueKey)

resp, err := c.Run(ctx, taskReq)
if err != nil {
return parseGRPCError(err, conn, &isConnClosed)
return parseGRPCError(err)
}

if resp.Error == "" {
Expand All @@ -73,11 +69,9 @@ func Exec(ip string, port int, taskReq *pb.TaskRequest) (string, error) {
return resp.Output, errors.New(resp.Error)
}

func parseGRPCError(err error, conn *grpc.ClientConn, connClosed *bool) (string, error) {
func parseGRPCError(err error) (string, error) {
switch grpc.Code(err) {
case codes.Unavailable, codes.Internal:
conn.Close()
*connClosed = true
case codes.Unavailable:
return "", errUnavailable
case codes.DeadlineExceeded:
return "", errors.New("执行超时, 强制结束")
Expand Down
163 changes: 71 additions & 92 deletions internal/modules/rpc/grpcpool/grpc_pool.go
Original file line number Diff line number Diff line change
@@ -1,140 +1,119 @@
package grpcpool

import (
"errors"
"context"
"strings"
"sync"
"time"

"github.com/ouqiang/gocron/internal/modules/app"
"github.com/ouqiang/gocron/internal/modules/rpc/auth"
"github.com/silenceper/pool"
"github.com/ouqiang/gocron/internal/modules/rpc/proto"
"google.golang.org/grpc"
"google.golang.org/grpc/keepalive"
)

var (
Pool GRPCPool
const (
backOffMaxDelay = 3 * time.Second
dialTimeout = 2 * time.Second
)

var (
ErrInvalidConn = errors.New("invalid connection")
)
Pool = &GRPCPool{
conns: make(map[string]*Client),
}

func init() {
Pool = GRPCPool{
make(map[string]pool.Pool),
sync.RWMutex{},
keepAliveParams = keepalive.ClientParameters{
Time: 20 * time.Second,
Timeout: 3 * time.Second,
PermitWithoutStream: true,
}
)

type Client struct {
conn *grpc.ClientConn
rpcClient rpc.TaskClient
}

type GRPCPool struct {
// map key格式 ip:port
conns map[string]pool.Pool
sync.RWMutex
conns map[string]*Client
mu sync.RWMutex
}

func (p *GRPCPool) Get(addr string) (*grpc.ClientConn, error) {
p.RLock()
pool, ok := p.conns[addr]
p.RUnlock()
if !ok {
err := p.newCommonPool(addr)
if err != nil {
return nil, err
}
func (p *GRPCPool) Get(addr string) (rpc.TaskClient, error) {
p.mu.RLock()
client, ok := p.conns[addr]
p.mu.RUnlock()
if ok {
return client.rpcClient, nil
}

p.RLock()
pool = p.conns[addr]
p.RUnlock()
conn, err := pool.Get()
client, err := p.factory(addr)
if err != nil {
return nil, err
}
p.conns[addr] = client

return conn.(*grpc.ClientConn), nil
return client.rpcClient, nil
}

func (p *GRPCPool) Put(addr string, conn *grpc.ClientConn) error {
p.RLock()
defer p.RUnlock()
pool, ok := p.conns[addr]
if ok {
return pool.Put(conn)
}

return ErrInvalidConn
}

// 释放连接池
// 释放连接
func (p *GRPCPool) Release(addr string) {
p.Lock()
defer p.Unlock()
pool, ok := p.conns[addr]
p.mu.Lock()
defer p.mu.Unlock()
client, ok := p.conns[addr]
if !ok {
return
}
pool.Release()
delete(p.conns, addr)
client.conn.Close()
}

// 释放所有连接池
func (p *GRPCPool) ReleaseAll() {
p.Lock()
defer p.Unlock()
for _, pool := range p.conns {
pool.Release()
}
}
// 创建连接
func (p *GRPCPool) factory(addr string) (*Client, error) {
p.mu.Lock()
defer p.mu.Unlock()

// 初始化底层连接池
func (p *GRPCPool) newCommonPool(addr string) error {
p.Lock()
defer p.Unlock()
commonPool, ok := p.conns[addr]
client, ok := p.conns[addr]
if ok {
return nil
return client, nil
}
poolConfig := &pool.PoolConfig{
InitialCap: 1,
MaxCap: 30,
Factory: func() (interface{}, error) {
if !app.Setting.EnableTLS {
return grpc.Dial(addr, grpc.WithInsecure())
}

server := strings.Split(addr, ":")

certificate := auth.Certificate{
CAFile: app.Setting.CAFile,
CertFile: app.Setting.CertFile,
KeyFile: app.Setting.KeyFile,
ServerName: server[0],
}

transportCreds, err := certificate.GetTransportCredsForClient()
if err != nil {
return nil, err
}

return grpc.Dial(addr, grpc.WithTransportCredentials(transportCreds))
},
Close: func(v interface{}) error {
conn, ok := v.(*grpc.ClientConn)
if ok && conn != nil {
return conn.Close()
}
return ErrInvalidConn
},
IdleTimeout: 3 * time.Minute,
opts := []grpc.DialOption{
grpc.WithKeepaliveParams(keepAliveParams),
grpc.WithBackoffMaxDelay(backOffMaxDelay),
}

commonPool, err := pool.NewChannelPool(poolConfig)
if !app.Setting.EnableTLS {
opts = append(opts, grpc.WithInsecure())
} else {
server := strings.Split(addr, ":")
certificate := auth.Certificate{
CAFile: app.Setting.CAFile,
CertFile: app.Setting.CertFile,
KeyFile: app.Setting.KeyFile,
ServerName: server[0],
}

transportCreds, err := certificate.GetTransportCredsForClient()
if err != nil {
return nil, err
}
opts = append(opts, grpc.WithTransportCredentials(transportCreds))
}

ctx, cancel := context.WithTimeout(context.Background(), dialTimeout)
defer cancel()

conn, err := grpc.DialContext(ctx, addr, opts...)
if err != nil {
return err
return nil, err
}

p.conns[addr] = commonPool
client = &Client{
conn: conn,
rpcClient: rpc.NewTaskClient(conn),
}

return nil
return client, nil
}
35 changes: 27 additions & 8 deletions internal/modules/rpc/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package server

import (
"net"
"time"

"google.golang.org/grpc/keepalive"

"github.com/ouqiang/gocron/internal/modules/rpc/auth"
pb "github.com/ouqiang/gocron/internal/modules/rpc/proto"
Expand All @@ -14,6 +17,19 @@ import (

type Server struct{}

var keepAlivePolicy = keepalive.EnforcementPolicy{
MinTime: 10 * time.Second,
PermitWithoutStream: true,
}

var keepAliveParams = keepalive.ServerParameters{
MaxConnectionIdle: 1 * time.Minute,
MaxConnectionAge: 2 * time.Hour,
MaxConnectionAgeGrace: 3 * time.Hour,
Time: 30 * time.Second,
Timeout: 3 * time.Second,
}

func (s Server) Run(ctx context.Context, req *pb.TaskRequest) (*pb.TaskResponse, error) {
defer func() {
if err := recover(); err != nil {
Expand All @@ -39,21 +55,24 @@ func Start(addr string, enableTLS bool, certificate auth.Certificate) {
}

var s *grpc.Server
opts := []grpc.ServerOption{
grpc.KeepaliveParams(keepAliveParams),
grpc.KeepaliveEnforcementPolicy(keepAlivePolicy),
}
if enableTLS {
tlsConfig, err := certificate.GetTLSConfigForServer()
if err != nil {
grpclog.Fatal(err)
}
opt := grpc.Creds(credentials.NewTLS(tlsConfig))
s = grpc.NewServer(opt)
pb.RegisterTaskServer(s, Server{})
grpclog.Printf("listen %s with TLS", addr)
} else {
s = grpc.NewServer()
pb.RegisterTaskServer(s, Server{})
grpclog.Printf("listen %s", addr)
opts = append(opts, opt)
}
s = grpc.NewServer(opts...)
pb.RegisterTaskServer(s, Server{})
grpclog.Printf("server listen on %s", addr)

err = s.Serve(l)
grpclog.Fatal(err)
if err != nil {
grpclog.Fatal(err)
}
}
6 changes: 5 additions & 1 deletion internal/routers/task/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"strconv"
"strings"

"github.com/ouqiang/goutil"

"github.com/go-macaron/binding"
"github.com/jakecoffman/cron"
"github.com/ouqiang/gocron/internal/models"
Expand Down Expand Up @@ -149,7 +151,9 @@ func Store(ctx *macaron.Context, form TaskForm) string {
}

if taskModel.Level == models.TaskLevelParent {
_, err = cron.Parse(form.Spec)
err = goutil.PanicToError(func() {
cron.Parse(form.Spec)
})
if err != nil {
return json.CommonFailure("crontab表达式解析失败", err)
}
Expand Down
6 changes: 5 additions & 1 deletion internal/service/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"sync"
"time"

"github.com/ouqiang/goutil"

"github.com/jakecoffman/cron"
"github.com/ouqiang/gocron/internal/models"
"github.com/ouqiang/gocron/internal/modules/app"
Expand Down Expand Up @@ -160,7 +162,9 @@ func (task Task) Add(taskModel models.Task) {
}

cronName := strconv.Itoa(taskModel.Id)
err := serviceCron.AddFunc(taskModel.Spec, taskFunc, cronName)
err := goutil.PanicToError(func() {
serviceCron.AddFunc(taskModel.Spec, taskFunc, cronName)
})
if err != nil {
logger.Error("添加任务到调度器失败#", err)
}
Expand Down
Loading

0 comments on commit c997ce7

Please sign in to comment.