mirror of
https://github.com/HDT3213/godis.git
synced 2025-10-07 01:32:56 +08:00
bug fix: do not client during closing
This commit is contained in:
@@ -11,9 +11,16 @@ import (
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
created = iota
|
||||
running
|
||||
closed
|
||||
)
|
||||
|
||||
// Client is a pipeline mode redis client
|
||||
type Client struct {
|
||||
conn net.Conn
|
||||
@@ -22,6 +29,7 @@ type Client struct {
|
||||
ticker *time.Ticker
|
||||
addr string
|
||||
|
||||
status int32
|
||||
working *sync.WaitGroup // its counter presents unfinished requests(pending and waiting)
|
||||
}
|
||||
|
||||
@@ -61,10 +69,12 @@ func (client *Client) Start() {
|
||||
go client.handleWrite()
|
||||
go client.handleRead()
|
||||
go client.heartbeat()
|
||||
atomic.StoreInt32(&client.status, running)
|
||||
}
|
||||
|
||||
// Close stops asynchronous goroutines and close connection
|
||||
func (client *Client) Close() {
|
||||
atomic.StoreInt32(&client.status, closed)
|
||||
client.ticker.Stop()
|
||||
// stop new request
|
||||
close(client.pendingReqs)
|
||||
@@ -78,6 +88,7 @@ func (client *Client) Close() {
|
||||
}
|
||||
|
||||
func (client *Client) reconnect() {
|
||||
logger.Info("reconnect with: " + client.addr)
|
||||
_ = client.conn.Close() // ignore possible errors from repeated closes
|
||||
|
||||
var conn net.Conn
|
||||
@@ -97,7 +108,7 @@ func (client *Client) reconnect() {
|
||||
return
|
||||
}
|
||||
client.conn = conn
|
||||
//
|
||||
|
||||
close(client.waitingReqs)
|
||||
for req := range client.waitingReqs {
|
||||
req.err = errors.New("connection closed")
|
||||
@@ -122,6 +133,9 @@ func (client *Client) handleWrite() {
|
||||
|
||||
// Send sends a request to redis server
|
||||
func (client *Client) Send(args [][]byte) redis.Reply {
|
||||
if atomic.LoadInt32(&client.status) != running {
|
||||
return protocol.MakeErrReply("client closed")
|
||||
}
|
||||
request := &request{
|
||||
args: args,
|
||||
heartbeat: false,
|
||||
@@ -198,6 +212,10 @@ func (client *Client) handleRead() {
|
||||
ch := parser.ParseStream(client.conn)
|
||||
for payload := range ch {
|
||||
if payload.Err != nil {
|
||||
status := atomic.LoadInt32(&client.status)
|
||||
if status == closed {
|
||||
return
|
||||
}
|
||||
client.reconnect()
|
||||
return
|
||||
}
|
||||
|
@@ -3,7 +3,9 @@ package client
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/hdt3213/godis/lib/logger"
|
||||
"github.com/hdt3213/godis/lib/utils"
|
||||
"github.com/hdt3213/godis/redis/protocol"
|
||||
"github.com/hdt3213/godis/redis/protocol/asserts"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -105,6 +107,8 @@ func TestClient(t *testing.T) {
|
||||
}
|
||||
|
||||
client.Close()
|
||||
ret := client.Send(utils.ToCmdLine("ping"))
|
||||
asserts.AssertErrReply(t, ret, "client closed")
|
||||
}
|
||||
|
||||
func TestReconnect(t *testing.T) {
|
||||
@@ -135,7 +139,4 @@ func TestReconnect(t *testing.T) {
|
||||
if !success {
|
||||
t.Error("reconnect error")
|
||||
}
|
||||
//var wg sync.WaitGroup
|
||||
//wg.Add(1)
|
||||
//wg.Wait()
|
||||
}
|
||||
|
Reference in New Issue
Block a user