github.com/polarismesh/polaris@v1.17.8/config/connection_manager.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package config 19 20 import ( 21 "context" 22 "sync" 23 "time" 24 25 apiconfig "github.com/polarismesh/specification/source/go/api/v1/config_manage" 26 27 api "github.com/polarismesh/polaris/common/api/v1" 28 "github.com/polarismesh/polaris/common/hash" 29 "github.com/polarismesh/polaris/common/utils" 30 ) 31 32 const ( 33 defaultLongPollingTimeout = 30000 * time.Millisecond 34 ) 35 36 type ClientConn struct { 37 once sync.Once 38 finishTime time.Time 39 finishChan chan *apiconfig.ConfigClientResponse 40 watchConfigFiles []*apiconfig.ClientConfigFileInfo 41 } 42 43 func (c *ClientConn) reply(rsp *apiconfig.ConfigClientResponse) { 44 c.once.Do(func() { 45 c.finishChan <- rsp 46 close(c.finishChan) 47 }) 48 } 49 50 type connManager struct { 51 watchCenter *watchCenter 52 conns *utils.SegmentMap[string, *ClientConn] // client -> ClientConn 53 stopWorkerFunc context.CancelFunc 54 } 55 56 var ( 57 notModifiedResponse = &apiconfig.ConfigClientResponse{ 58 Code: utils.NewUInt32Value(api.DataNoChange), 59 ConfigFile: nil, 60 } 61 62 cm *connManager 63 ) 64 65 // NewConfigConnManager 初始化连接管理器,定时响应超时的请求 66 func NewConfigConnManager(ctx context.Context, watchCenter *watchCenter) *connManager { 67 cm = &connManager{ 68 conns: utils.NewSegmentMap[string, *ClientConn](128, hash.Fnv32), 69 watchCenter: watchCenter, 70 } 71 72 go cm.startHandleTimeoutRequestWorker(ctx) 73 74 return cm 75 } 76 77 func (c *connManager) AddConn( 78 clientId string, files []*apiconfig.ClientConfigFileInfo) chan *apiconfig.ConfigClientResponse { 79 80 finishChan := make(chan *apiconfig.ConfigClientResponse) 81 82 cm.conns.Put(clientId, &ClientConn{ 83 finishTime: time.Now().Add(defaultLongPollingTimeout), 84 finishChan: finishChan, 85 watchConfigFiles: files, 86 }) 87 88 c.watchCenter.AddWatcher(clientId, files, func(clientId string, rsp *apiconfig.ConfigClientResponse) bool { 89 if conn, ok := cm.conns.Get(clientId); ok { 90 conn.reply(rsp) 91 c.removeConn(clientId) 92 } 93 return true 94 }) 95 96 return finishChan 97 } 98 99 func (c *connManager) removeConn(clientId string) { 100 conn, ok := cm.conns.Get(clientId) 101 if !ok { 102 return 103 } 104 c.watchCenter.RemoveWatcher(clientId, conn.watchConfigFiles) 105 cm.conns.Del(clientId) 106 } 107 108 func (c *connManager) startHandleTimeoutRequestWorker(ctx context.Context) { 109 t := time.NewTicker(time.Second) 110 defer t.Stop() 111 for { 112 select { 113 case <-ctx.Done(): 114 return 115 case <-t.C: 116 if cm.conns == nil { 117 continue 118 } 119 tNow := time.Now() 120 cm.conns.Range(func(client string, conn *ClientConn) { 121 if tNow.After(conn.finishTime) { 122 conn.reply(notModifiedResponse) 123 c.removeConn(client) 124 } 125 }) 126 } 127 } 128 }