fix: unable to connect to any server after manually interrupt

This commit is contained in:
Lykin 2024-06-18 18:00:46 +08:00
parent 8c30daec15
commit 6bd1b23a64
2 changed files with 33 additions and 72 deletions

View File

@ -233,13 +233,12 @@ func (b *browserService) OpenConnection(name string) (resp types.JSResp) {
// CloseConnection close redis server connection // CloseConnection close redis server connection
func (b *browserService) CloseConnection(name string) (resp types.JSResp) { func (b *browserService) CloseConnection(name string) (resp types.JSResp) {
item, ok := b.connMap[name] if item, ok := b.connMap[name]; ok {
if ok {
delete(b.connMap, name) delete(b.connMap, name)
if item.client != nil {
if item.cancelFunc != nil { if item.cancelFunc != nil {
item.cancelFunc() item.cancelFunc()
} }
if item.client != nil {
item.client.Close() item.client.Close()
} }
} }
@ -247,7 +246,7 @@ func (b *browserService) CloseConnection(name string) (resp types.JSResp) {
return return
} }
func (b *browserService) createRedisClient(selConn types.ConnectionConfig) (client redis.UniversalClient, err error) { func (b *browserService) createRedisClient(ctx context.Context, selConn types.ConnectionConfig) (client redis.UniversalClient, err error) {
hook := redis2.NewHook(selConn.Name, func(cmd string, cost int64) { hook := redis2.NewHook(selConn.Name, func(cmd string, cost int64) {
now := time.Now() now := time.Now()
//last := strings.LastIndex(cmd, ":") //last := strings.LastIndex(cmd, ":")
@ -268,10 +267,10 @@ func (b *browserService) createRedisClient(selConn types.ConnectionConfig) (clie
return return
} }
_ = client.Do(b.ctx, "CLIENT", "SETNAME", url.QueryEscape(selConn.Name)).Err() _ = client.Do(ctx, "CLIENT", "SETNAME", url.QueryEscape(selConn.Name)).Err()
// add hook to each node in cluster mode // add hook to each node in cluster mode
if cluster, ok := client.(*redis.ClusterClient); ok { if cluster, ok := client.(*redis.ClusterClient); ok {
err = cluster.ForEachShard(b.ctx, func(ctx context.Context, cli *redis.Client) error { err = cluster.ForEachShard(ctx, func(ctx context.Context, cli *redis.Client) error {
cli.AddHook(hook) cli.AddHook(hook)
return nil return nil
}) })
@ -283,7 +282,7 @@ func (b *browserService) createRedisClient(selConn types.ConnectionConfig) (clie
client.AddHook(hook) client.AddHook(hook)
} }
if _, err = client.Ping(b.ctx).Result(); err != nil && !errors.Is(err, redis.Nil) { if _, err = client.Ping(ctx).Result(); err != nil && !errors.Is(err, redis.Nil) {
err = errors.New("can not connect to redis server:" + err.Error()) err = errors.New("can not connect to redis server:" + err.Error())
return return
} }
@ -318,13 +317,18 @@ func (b *browserService) getRedisClient(server string, db int) (item *connection
err = fmt.Errorf("no match connection \"%s\"", server) err = fmt.Errorf("no match connection \"%s\"", server)
return return
} }
ctx, cancelFunc := context.WithCancel(b.ctx)
b.connMap[server] = &connectionItem{
ctx: ctx,
cancelFunc: cancelFunc,
}
var connConfig = selConn.ConnectionConfig var connConfig = selConn.ConnectionConfig
connConfig.LastDB = db connConfig.LastDB = db
client, err = b.createRedisClient(connConfig) client, err = b.createRedisClient(ctx, connConfig)
if err != nil { if err != nil {
return return
} }
ctx, cancelFunc := context.WithCancel(b.ctx)
item = &connectionItem{ item = &connectionItem{
client: client, client: client,
ctx: ctx, ctx: ctx,
@ -2009,21 +2013,13 @@ func (b *browserService) SetKeyTTL(server string, db int, k any, ttl int64) (res
// BatchSetTTL batch set ttl // BatchSetTTL batch set ttl
func (b *browserService) BatchSetTTL(server string, db int, ks []any, ttl int64, serialNo string) (resp types.JSResp) { func (b *browserService) BatchSetTTL(server string, db int, ks []any, ttl int64, serialNo string) (resp types.JSResp) {
conf := Connection().getConnection(server) item, err := b.getRedisClient(server, db)
if conf == nil { if err != nil {
resp.Msg = fmt.Sprintf("no connection profile named: %s", server)
return
}
var client redis.UniversalClient
var err error
var connConfig = conf.ConnectionConfig
connConfig.LastDB = db
if client, err = b.createRedisClient(connConfig); err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return
} }
client := item.client
ctx, cancelFunc := context.WithCancel(b.ctx) ctx, cancelFunc := context.WithCancel(b.ctx)
defer client.Close()
defer cancelFunc() defer cancelFunc()
//cancelEvent := "ttling:stop:" + serialNo //cancelEvent := "ttling:stop:" + serialNo
@ -2047,7 +2043,7 @@ func (b *browserService) BatchSetTTL(server string, db int, ks []any, ttl int64,
//} //}
if i >= total-1 || time.Now().Sub(startTime).Milliseconds() > 100 { if i >= total-1 || time.Now().Sub(startTime).Milliseconds() > 100 {
startTime = time.Now() startTime = time.Now()
//runtime.EventsEmit(b.ctx, processEvent, param) //runtime.EventsEmit(ctx, processEvent, param)
// do some sleep to prevent blocking the Redis server // do some sleep to prevent blocking the Redis server
time.Sleep(10 * time.Millisecond) time.Sleep(10 * time.Millisecond)
} }
@ -2217,22 +2213,13 @@ func (b *browserService) DeleteOneKey(server string, db int, k any) (resp types.
// DeleteKeys delete keys sync with notification // DeleteKeys delete keys sync with notification
func (b *browserService) DeleteKeys(server string, db int, ks []any, serialNo string) (resp types.JSResp) { func (b *browserService) DeleteKeys(server string, db int, ks []any, serialNo string) (resp types.JSResp) {
// connect a new connection to export keys item, err := b.getRedisClient(server, db)
conf := Connection().getConnection(server) if err != nil {
if conf == nil {
resp.Msg = fmt.Sprintf("no connection profile named: %s", server)
return
}
var client redis.UniversalClient
var err error
var connConfig = conf.ConnectionConfig
connConfig.LastDB = db
if client, err = b.createRedisClient(connConfig); err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return
} }
client := item.client
ctx, cancelFunc := context.WithCancel(b.ctx) ctx, cancelFunc := context.WithCancel(b.ctx)
defer client.Close()
defer cancelFunc() defer cancelFunc()
cancelEvent := "delete:stop:" + serialNo cancelEvent := "delete:stop:" + serialNo
@ -2294,21 +2281,13 @@ func (b *browserService) DeleteKeys(server string, db int, ks []any, serialNo st
// DeleteKeysByPattern delete keys by pattern // DeleteKeysByPattern delete keys by pattern
func (b *browserService) DeleteKeysByPattern(server string, db int, pattern string) (resp types.JSResp) { func (b *browserService) DeleteKeysByPattern(server string, db int, pattern string) (resp types.JSResp) {
conf := Connection().getConnection(server) item, err := b.getRedisClient(server, db)
if conf == nil { if err != nil {
resp.Msg = fmt.Sprintf("no connection profile named: %s", server)
return
}
var client redis.UniversalClient
var err error
var connConfig = conf.ConnectionConfig
connConfig.LastDB = db
if client, err = b.createRedisClient(connConfig); err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return
} }
client := item.client
ctx, cancelFunc := context.WithCancel(b.ctx) ctx, cancelFunc := context.WithCancel(b.ctx)
defer client.Close()
defer cancelFunc() defer cancelFunc()
var ks []any var ks []any
@ -2372,22 +2351,13 @@ func (b *browserService) DeleteKeysByPattern(server string, db int, pattern stri
// ExportKey export keys // ExportKey export keys
func (b *browserService) ExportKey(server string, db int, ks []any, path string, includeExpire bool) (resp types.JSResp) { func (b *browserService) ExportKey(server string, db int, ks []any, path string, includeExpire bool) (resp types.JSResp) {
// connect a new connection to export keys item, err := b.getRedisClient(server, db)
conf := Connection().getConnection(server) if err != nil {
if conf == nil {
resp.Msg = fmt.Sprintf("no connection profile named: %s", server)
return
}
var client redis.UniversalClient
var err error
var connConfig = conf.ConnectionConfig
connConfig.LastDB = db
if client, err = b.createRedisClient(connConfig); err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return
} }
client := item.client
ctx, cancelFunc := context.WithCancel(b.ctx) ctx, cancelFunc := context.WithCancel(b.ctx)
defer client.Close()
defer cancelFunc() defer cancelFunc()
file, err := os.Create(path) file, err := os.Create(path)
@ -2456,22 +2426,13 @@ func (b *browserService) ExportKey(server string, db int, ks []any, path string,
// ImportCSV import data from csv file // ImportCSV import data from csv file
func (b *browserService) ImportCSV(server string, db int, path string, conflict int, ttl int64) (resp types.JSResp) { func (b *browserService) ImportCSV(server string, db int, path string, conflict int, ttl int64) (resp types.JSResp) {
// connect a new connection to export keys item, err := b.getRedisClient(server, db)
conf := Connection().getConnection(server) if err != nil {
if conf == nil {
resp.Msg = fmt.Sprintf("no connection profile named: %s", server)
return
}
var client redis.UniversalClient
var err error
var connConfig = conf.ConnectionConfig
connConfig.LastDB = db
if client, err = b.createRedisClient(connConfig); err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return
} }
client := item.client
ctx, cancelFunc := context.WithCancel(b.ctx) ctx, cancelFunc := context.WithCancel(b.ctx)
defer client.Close()
defer cancelFunc() defer cancelFunc()
file, err := os.Open(path) file, err := os.Open(path)
@ -2553,7 +2514,7 @@ func (b *browserService) ImportCSV(server string, db int, path string, conflict
"ignored": ignored, "ignored": ignored,
//"processing": string(key), //"processing": string(key),
} }
runtime.EventsEmit(b.ctx, processEvent, param) runtime.EventsEmit(ctx, processEvent, param)
// do some sleep to prevent blocking the Redis server // do some sleep to prevent blocking the Redis server
time.Sleep(10 * time.Millisecond) time.Sleep(10 * time.Millisecond)
} }

View File

@ -130,7 +130,7 @@ const onClose = () => {
required> required>
<n-input v-model:value="deleteForm.key" placeholder="" @input="resetAffected" /> <n-input v-model:value="deleteForm.key" placeholder="" @input="resetAffected" />
</n-form-item> </n-form-item>
<n-checkbox v-model:checked="deleteForm.direct"> <n-checkbox v-if="!deleteForm.showAffected" v-model:checked="deleteForm.direct">
{{ $t('dialogue.key.direct_delete') }} {{ $t('dialogue.key.direct_delete') }}
</n-checkbox> </n-checkbox>
<n-card <n-card