refactor: pool get options支持不创建连接

This commit is contained in:
meilin.huang
2025-05-29 20:24:48 +08:00
parent 42fbfd3c47
commit 7a17042276
15 changed files with 59 additions and 59 deletions

View File

@@ -13,7 +13,7 @@
"@element-plus/icons-vue": "^2.3.1",
"@logicflow/core": "^2.0.13",
"@logicflow/extension": "^2.0.18",
"@vueuse/core": "^13.2.0",
"@vueuse/core": "^13.3.0",
"@xterm/addon-fit": "^0.10.0",
"@xterm/addon-search": "^0.15.0",
"@xterm/addon-web-links": "^0.11.0",
@@ -36,12 +36,12 @@
"qrcode.vue": "^3.6.0",
"screenfull": "^6.0.2",
"sortablejs": "^1.15.6",
"splitpanes": "^4.0.3",
"splitpanes": "^4.0.4",
"sql-formatter": "^15.6.1",
"trzsz": "^1.1.5",
"uuid": "^9.0.1",
"vue": "^3.5.14",
"vue-i18n": "^11.1.3",
"vue": "^3.5.16",
"vue-i18n": "^11.1.5",
"vue-router": "^4.5.1",
"vuedraggable": "^4.1.0"
},
@@ -54,16 +54,16 @@
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"@vitejs/plugin-vue": "^5.2.4",
"@vue/compiler-sfc": "^3.5.14",
"@vue/compiler-sfc": "^3.5.16",
"autoprefixer": "^10.4.21",
"code-inspector-plugin": "^0.20.9",
"dotenv": "^16.3.1",
"eslint": "^9.25.1",
"eslint-plugin-vue": "^10.0.0",
"postcss": "^8.5.3",
"eslint": "^9.27.0",
"eslint-plugin-vue": "^10.1.0",
"postcss": "^8.5.4",
"prettier": "^3.5.3",
"sass": "^1.89.0",
"tailwindcss": "^4.1.7",
"tailwindcss": "^4.1.8",
"typescript": "^5.8.2",
"vite": "^6.3.5",
"vite-plugin-progress": "0.0.7",

View File

@@ -19,7 +19,7 @@ type DataSyncTaskListVO struct {
type DataSyncLogListVO struct {
CreateTime *time.Time `json:"createTime"`
DataSqlFull string `json:"dataSqlFull"`
ResNum string `json:"resNum"`
ResNum int `json:"resNum"`
ErrText string `json:"errText"`
Status *int `json:"status"`
}

View File

@@ -17,16 +17,6 @@ func InitIoc() {
func Init() {
sync.OnceFunc(func() {
//if err := GetDbBackupApp().Init(); err != nil {
// panic(fmt.Sprintf("初始化 DbBackupApp 失败: %v", err))
//}
//if err := GetDbRestoreApp().Init(); err != nil {
// panic(fmt.Sprintf("初始化 DbRestoreApp 失败: %v", err))
//}
//if err := GetDbBinlogApp().Init(); err != nil {
// panic(fmt.Sprintf("初始化 DbBinlogApp 失败: %v", err))
//}
GetDataSyncTaskApp().InitCronJob()
GetDbTransferTaskApp().InitCronJob()
GetDbTransferTaskApp().TimerDeleteTransferFile()

View File

@@ -76,6 +76,7 @@ func (app *dataSyncAppImpl) Save(ctx context.Context, taskEntity *entity.DataSyn
taskEntity.TaskKey = uuid.New().String()
err = app.Insert(ctx, taskEntity)
} else {
taskEntity.TaskKey = ""
err = app.UpdateById(ctx, taskEntity)
}
@@ -107,15 +108,13 @@ func (app *dataSyncAppImpl) AddCronJob(ctx context.Context, taskEntity *entity.D
// 根据状态添加新的任务
if taskEntity.Status == entity.DataSyncTaskStatusEnable {
taskId := taskEntity.Id
logx.Infof("start add the data sync task job: %s, cron[%s]", taskEntity.TaskName, taskEntity.TaskCron)
if err := scheduler.AddFunByKey(key, taskEntity.TaskCron, func() {
logx.Infof("start the data synchronization task: %d", taskId)
cancelCtx, cancelFunc := context.WithCancel(ctx)
defer cancelFunc()
if err := app.RunCronJob(cancelCtx, taskId); err != nil {
logx.Errorf("the data synchronization task failed to execute at a scheduled time: %s", err.Error())
if err := app.RunCronJob(context.Background(), taskId); err != nil {
logx.Errorf("the data sync task failed to execute at a scheduled time: %s", err.Error())
}
}); err != nil {
logx.ErrorTrace("add db data sync cron job failed", err)
logx.ErrorTrace("add db data sync job failed", err)
}
}
}
@@ -133,6 +132,9 @@ func (app *dataSyncAppImpl) RunCronJob(ctx context.Context, id uint64) error {
if err != nil {
return errorx.NewBiz("task not found")
}
logx.InfofContext(ctx, "start the data sync task: %s => %s", task.TaskName, task.TaskKey)
if task.RunningState == entity.DataSyncTaskRunStateRunning {
return errorx.NewBiz("the task is in progress")
}
@@ -140,8 +142,6 @@ func (app *dataSyncAppImpl) RunCronJob(ctx context.Context, id uint64) error {
// 标记该任务运行中
app.MarkRunning(id)
logx.InfofContext(ctx, "start the data synchronization task: %s => %s", task.TaskName, task.TaskKey)
go func() {
// 通过占位符格式化sql
updSql := ""

View File

@@ -22,10 +22,7 @@ func init() {
mcm.AddCheckSshTunnelMachineUseFunc(func(machineId int) bool {
items := poolGroup.AllPool()
for _, v := range items {
if v.Stats().TotalConns == 0 {
continue // 连接池中没有连接,跳过
}
conn, err := v.Get(context.Background(), pool.WithNoUpdateLastActive())
conn, err := v.Get(context.Background(), pool.WithGetNoUpdateLastActive(), pool.WithGetNoNewConn())
if err != nil {
continue // 获取连接失败,跳过
}

View File

@@ -45,10 +45,7 @@ func init() {
mcm.AddCheckSshTunnelMachineUseFunc(func(machineId int) bool {
items := poolGroup.AllPool()
for _, v := range items {
if v.Stats().TotalConns == 0 {
continue // 连接池中没有连接,跳过
}
conn, err := v.Get(context.Background(), pool.WithNoUpdateLastActive())
conn, err := v.Get(context.Background(), pool.WithGetNoUpdateLastActive(), pool.WithGetNoNewConn())
if err != nil {
continue // 获取连接失败,跳过
}

View File

@@ -18,7 +18,7 @@ import (
type EsVersion string
type EsInfo struct {
model.ExtraData // 连接需要的其他额外参数json字符串如oracle数据库需要指定sid等
model.ExtraData // 连接需要的其他额外参数json字符串
InstanceId uint64 // 实例id
Name string

View File

@@ -53,10 +53,7 @@ func GetMachineCli(ctx context.Context, authCertName string, getMachine func(str
// 删除指定机器缓存客户端,并关闭客户端连接
func DeleteCli(id uint64) {
for _, p := range poolGroup.AllPool() {
if p.Stats().TotalConns == 0 {
continue
}
conn, err := p.Get(context.Background(), pool.WithNoUpdateLastActive())
conn, err := p.Get(context.Background(), pool.WithGetNoUpdateLastActive(), pool.WithGetNoNewConn())
if err != nil {
continue
}

View File

@@ -14,10 +14,7 @@ func init() {
mcm.AddCheckSshTunnelMachineUseFunc(func(machineId int) bool {
items := poolGroup.AllPool()
for _, v := range items {
if v.Stats().TotalConns == 0 {
continue // 连接池中没有连接,跳过
}
conn, err := v.Get(context.Background(), pool.WithNoUpdateLastActive())
conn, err := v.Get(context.Background(), pool.WithGetNoUpdateLastActive(), pool.WithGetNoNewConn())
if err != nil {
continue // 获取连接失败,跳过
}

View File

@@ -174,8 +174,7 @@ func (r *redisAppImpl) Delete(ctx context.Context, id uint64) error {
}
// 如果存在连接,则关闭所有库连接信息
for _, dbStr := range strings.Split(re.Db, ",") {
db, _ := strconv.Atoi(dbStr)
rdm.CloseConn(re.Id, db)
rdm.CloseConn(re.Id, cast.ToInt(dbStr))
}
return r.Tx(ctx, func(ctx context.Context) error {

View File

@@ -15,10 +15,7 @@ func init() {
// 遍历所有redis连接实例若存在redis实例使用该ssh隧道机器则返回true表示还在使用中...
items := poolGroup.AllPool()
for _, v := range items {
if v.Stats().TotalConns == 0 {
continue // 连接池中没有连接,跳过
}
rc, err := v.Get(context.Background(), pool.WithNoUpdateLastActive())
rc, err := v.Get(context.Background(), pool.WithGetNoUpdateLastActive(), pool.WithGetNoNewConn())
if err != nil {
continue // 获取连接失败,跳过
}

View File

@@ -49,7 +49,7 @@ func NewCachePool[T Conn](factory func() (T, error), opts ...Option[T]) *CachePo
func (p *CachePool[T]) Get(ctx context.Context, opts ...GetOption) (T, error) {
var zero T
options := getOptions{updateLastActive: true} // 默认更新 lastActive
options := defaultGetOptions // 默认更新 lastActive
for _, apply := range opts {
apply(&options)
}
@@ -75,6 +75,10 @@ func (p *CachePool[T]) Get(ctx context.Context, opts ...GetOption) (T, error) {
}
p.mu.RUnlock()
if !options.newConn {
return zero, ErrNoAvailableConn
}
// 没有找到可用连接,升级为写锁进行创建
p.mu.Lock()
defer p.mu.Unlock()
@@ -241,6 +245,7 @@ func (p *CachePool[T]) ping(conn T) bool {
case <-done:
return result
case <-time.After(2 * time.Second): // 设置超时
logx.Debug("ping timeout")
return false // 超时认为不可用
}
}

View File

@@ -78,7 +78,7 @@ func (p *ChanPool[T]) Get(ctx context.Context, opts ...GetOption) (T, error) {
connChan := make(chan T, 1)
errChan := make(chan error, 1)
options := getOptions{updateLastActive: true} // 默认更新 lastActive
options := defaultGetOptions // 默认更新 lastActive
for _, apply := range opts {
apply(&options)
}
@@ -114,11 +114,11 @@ func (p *ChanPool[T]) Get(ctx context.Context, opts ...GetOption) (T, error) {
}
func (p *ChanPool[T]) get(opts getOptions) (T, error) {
var zero T
// 检查连接池是否已关闭
p.mu.RLock()
if p.closed {
p.mu.RUnlock()
var zero T
return zero, ErrPoolClosed
}
p.mu.RUnlock()
@@ -133,6 +133,9 @@ func (p *ChanPool[T]) get(opts getOptions) (T, error) {
}
return wrapper.conn, nil
default:
if !opts.newConn {
return zero, ErrNoAvailableConn
}
return p.createConn()
}
}

View File

@@ -5,7 +5,10 @@ import (
"time"
)
var ErrPoolClosed = errors.New("pool is closed")
var (
ErrPoolClosed = errors.New("pool is closed")
ErrNoAvailableConn = errors.New("no available connection")
)
// PoolConfig 连接池配置
type PoolConfig[T Conn] struct {
@@ -71,11 +74,26 @@ type GetOption func(*getOptions)
// 控制 Get 行为的选项
type getOptions struct {
updateLastActive bool // 是否更新 lastActive默认 true
newConn bool // 连接不存在时是否创建新连接,默认 true
}
// WithNoUpdateLastActive 返回一个 Option禁用更新 lastActive
func WithNoUpdateLastActive() GetOption {
var (
defaultGetOptions = getOptions{
updateLastActive: true,
newConn: true,
}
)
// WithGetNoUpdateLastActive 返回一个 Option禁用更新 lastActive
func WithGetNoUpdateLastActive() GetOption {
return func(o *getOptions) {
o.updateLastActive = false
}
}
// WithGetNoCreateConn 禁用获取时连接不存在创建连接
func WithGetNoNewConn() GetOption {
return func(o *getOptions) {
o.newConn = false
}
}

View File

@@ -117,8 +117,8 @@ func (pg *PoolGroup[T]) asyncClose(pool Pool[T], key string) {
select {
case <-done:
logx.Infof("pool group - pool closed successfully, key: %s", key)
case <-time.After(5 * time.Second):
logx.Errorf("pool group - pool close timeout, possible deadlock detected, key: %s", key)
case <-time.After(10 * time.Second):
logx.Errorf("pool group - pool close timeout, key: %s", key)
// 打印当前 goroutine 的堆栈信息
buf := make([]byte, 1<<16)
runtime.Stack(buf, true)