mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-04 00:10:25 +08:00
refactor: pool get options支持不创建连接
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"@logicflow/core": "^2.0.13",
|
"@logicflow/core": "^2.0.13",
|
||||||
"@logicflow/extension": "^2.0.18",
|
"@logicflow/extension": "^2.0.18",
|
||||||
"@vueuse/core": "^13.2.0",
|
"@vueuse/core": "^13.3.0",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/addon-search": "^0.15.0",
|
"@xterm/addon-search": "^0.15.0",
|
||||||
"@xterm/addon-web-links": "^0.11.0",
|
"@xterm/addon-web-links": "^0.11.0",
|
||||||
@@ -36,12 +36,12 @@
|
|||||||
"qrcode.vue": "^3.6.0",
|
"qrcode.vue": "^3.6.0",
|
||||||
"screenfull": "^6.0.2",
|
"screenfull": "^6.0.2",
|
||||||
"sortablejs": "^1.15.6",
|
"sortablejs": "^1.15.6",
|
||||||
"splitpanes": "^4.0.3",
|
"splitpanes": "^4.0.4",
|
||||||
"sql-formatter": "^15.6.1",
|
"sql-formatter": "^15.6.1",
|
||||||
"trzsz": "^1.1.5",
|
"trzsz": "^1.1.5",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"vue": "^3.5.14",
|
"vue": "^3.5.16",
|
||||||
"vue-i18n": "^11.1.3",
|
"vue-i18n": "^11.1.5",
|
||||||
"vue-router": "^4.5.1",
|
"vue-router": "^4.5.1",
|
||||||
"vuedraggable": "^4.1.0"
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
@@ -54,16 +54,16 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
||||||
"@typescript-eslint/parser": "^6.7.4",
|
"@typescript-eslint/parser": "^6.7.4",
|
||||||
"@vitejs/plugin-vue": "^5.2.4",
|
"@vitejs/plugin-vue": "^5.2.4",
|
||||||
"@vue/compiler-sfc": "^3.5.14",
|
"@vue/compiler-sfc": "^3.5.16",
|
||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
"code-inspector-plugin": "^0.20.9",
|
"code-inspector-plugin": "^0.20.9",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"eslint": "^9.25.1",
|
"eslint": "^9.27.0",
|
||||||
"eslint-plugin-vue": "^10.0.0",
|
"eslint-plugin-vue": "^10.1.0",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.4",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"sass": "^1.89.0",
|
"sass": "^1.89.0",
|
||||||
"tailwindcss": "^4.1.7",
|
"tailwindcss": "^4.1.8",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"vite": "^6.3.5",
|
"vite": "^6.3.5",
|
||||||
"vite-plugin-progress": "0.0.7",
|
"vite-plugin-progress": "0.0.7",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ type DataSyncTaskListVO struct {
|
|||||||
type DataSyncLogListVO struct {
|
type DataSyncLogListVO struct {
|
||||||
CreateTime *time.Time `json:"createTime"`
|
CreateTime *time.Time `json:"createTime"`
|
||||||
DataSqlFull string `json:"dataSqlFull"`
|
DataSqlFull string `json:"dataSqlFull"`
|
||||||
ResNum string `json:"resNum"`
|
ResNum int `json:"resNum"`
|
||||||
ErrText string `json:"errText"`
|
ErrText string `json:"errText"`
|
||||||
Status *int `json:"status"`
|
Status *int `json:"status"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,6 @@ func InitIoc() {
|
|||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
sync.OnceFunc(func() {
|
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()
|
GetDataSyncTaskApp().InitCronJob()
|
||||||
GetDbTransferTaskApp().InitCronJob()
|
GetDbTransferTaskApp().InitCronJob()
|
||||||
GetDbTransferTaskApp().TimerDeleteTransferFile()
|
GetDbTransferTaskApp().TimerDeleteTransferFile()
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ func (app *dataSyncAppImpl) Save(ctx context.Context, taskEntity *entity.DataSyn
|
|||||||
taskEntity.TaskKey = uuid.New().String()
|
taskEntity.TaskKey = uuid.New().String()
|
||||||
err = app.Insert(ctx, taskEntity)
|
err = app.Insert(ctx, taskEntity)
|
||||||
} else {
|
} else {
|
||||||
|
taskEntity.TaskKey = ""
|
||||||
err = app.UpdateById(ctx, taskEntity)
|
err = app.UpdateById(ctx, taskEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,15 +108,13 @@ func (app *dataSyncAppImpl) AddCronJob(ctx context.Context, taskEntity *entity.D
|
|||||||
// 根据状态添加新的任务
|
// 根据状态添加新的任务
|
||||||
if taskEntity.Status == entity.DataSyncTaskStatusEnable {
|
if taskEntity.Status == entity.DataSyncTaskStatusEnable {
|
||||||
taskId := taskEntity.Id
|
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() {
|
if err := scheduler.AddFunByKey(key, taskEntity.TaskCron, func() {
|
||||||
logx.Infof("start the data synchronization task: %d", taskId)
|
if err := app.RunCronJob(context.Background(), taskId); err != nil {
|
||||||
cancelCtx, cancelFunc := context.WithCancel(ctx)
|
logx.Errorf("the data sync task failed to execute at a scheduled time: %s", err.Error())
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
}); err != nil {
|
}); 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 {
|
if err != nil {
|
||||||
return errorx.NewBiz("task not found")
|
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 {
|
if task.RunningState == entity.DataSyncTaskRunStateRunning {
|
||||||
return errorx.NewBiz("the task is in progress")
|
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)
|
app.MarkRunning(id)
|
||||||
|
|
||||||
logx.InfofContext(ctx, "start the data synchronization task: %s => %s", task.TaskName, task.TaskKey)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// 通过占位符格式化sql
|
// 通过占位符格式化sql
|
||||||
updSql := ""
|
updSql := ""
|
||||||
|
|||||||
@@ -22,10 +22,7 @@ func init() {
|
|||||||
mcm.AddCheckSshTunnelMachineUseFunc(func(machineId int) bool {
|
mcm.AddCheckSshTunnelMachineUseFunc(func(machineId int) bool {
|
||||||
items := poolGroup.AllPool()
|
items := poolGroup.AllPool()
|
||||||
for _, v := range items {
|
for _, v := range items {
|
||||||
if v.Stats().TotalConns == 0 {
|
conn, err := v.Get(context.Background(), pool.WithGetNoUpdateLastActive(), pool.WithGetNoNewConn())
|
||||||
continue // 连接池中没有连接,跳过
|
|
||||||
}
|
|
||||||
conn, err := v.Get(context.Background(), pool.WithNoUpdateLastActive())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue // 获取连接失败,跳过
|
continue // 获取连接失败,跳过
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,7 @@ func init() {
|
|||||||
mcm.AddCheckSshTunnelMachineUseFunc(func(machineId int) bool {
|
mcm.AddCheckSshTunnelMachineUseFunc(func(machineId int) bool {
|
||||||
items := poolGroup.AllPool()
|
items := poolGroup.AllPool()
|
||||||
for _, v := range items {
|
for _, v := range items {
|
||||||
if v.Stats().TotalConns == 0 {
|
conn, err := v.Get(context.Background(), pool.WithGetNoUpdateLastActive(), pool.WithGetNoNewConn())
|
||||||
continue // 连接池中没有连接,跳过
|
|
||||||
}
|
|
||||||
conn, err := v.Get(context.Background(), pool.WithNoUpdateLastActive())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue // 获取连接失败,跳过
|
continue // 获取连接失败,跳过
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
type EsVersion string
|
type EsVersion string
|
||||||
|
|
||||||
type EsInfo struct {
|
type EsInfo struct {
|
||||||
model.ExtraData // 连接需要的其他额外参数(json字符串),如oracle数据库需要指定sid等
|
model.ExtraData // 连接需要的其他额外参数(json字符串)
|
||||||
|
|
||||||
InstanceId uint64 // 实例id
|
InstanceId uint64 // 实例id
|
||||||
Name string
|
Name string
|
||||||
|
|||||||
@@ -53,10 +53,7 @@ func GetMachineCli(ctx context.Context, authCertName string, getMachine func(str
|
|||||||
// 删除指定机器缓存客户端,并关闭客户端连接
|
// 删除指定机器缓存客户端,并关闭客户端连接
|
||||||
func DeleteCli(id uint64) {
|
func DeleteCli(id uint64) {
|
||||||
for _, p := range poolGroup.AllPool() {
|
for _, p := range poolGroup.AllPool() {
|
||||||
if p.Stats().TotalConns == 0 {
|
conn, err := p.Get(context.Background(), pool.WithGetNoUpdateLastActive(), pool.WithGetNoNewConn())
|
||||||
continue
|
|
||||||
}
|
|
||||||
conn, err := p.Get(context.Background(), pool.WithNoUpdateLastActive())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,7 @@ func init() {
|
|||||||
mcm.AddCheckSshTunnelMachineUseFunc(func(machineId int) bool {
|
mcm.AddCheckSshTunnelMachineUseFunc(func(machineId int) bool {
|
||||||
items := poolGroup.AllPool()
|
items := poolGroup.AllPool()
|
||||||
for _, v := range items {
|
for _, v := range items {
|
||||||
if v.Stats().TotalConns == 0 {
|
conn, err := v.Get(context.Background(), pool.WithGetNoUpdateLastActive(), pool.WithGetNoNewConn())
|
||||||
continue // 连接池中没有连接,跳过
|
|
||||||
}
|
|
||||||
conn, err := v.Get(context.Background(), pool.WithNoUpdateLastActive())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue // 获取连接失败,跳过
|
continue // 获取连接失败,跳过
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,8 +174,7 @@ func (r *redisAppImpl) Delete(ctx context.Context, id uint64) error {
|
|||||||
}
|
}
|
||||||
// 如果存在连接,则关闭所有库连接信息
|
// 如果存在连接,则关闭所有库连接信息
|
||||||
for _, dbStr := range strings.Split(re.Db, ",") {
|
for _, dbStr := range strings.Split(re.Db, ",") {
|
||||||
db, _ := strconv.Atoi(dbStr)
|
rdm.CloseConn(re.Id, cast.ToInt(dbStr))
|
||||||
rdm.CloseConn(re.Id, db)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.Tx(ctx, func(ctx context.Context) error {
|
return r.Tx(ctx, func(ctx context.Context) error {
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ func init() {
|
|||||||
// 遍历所有redis连接实例,若存在redis实例使用该ssh隧道机器,则返回true,表示还在使用中...
|
// 遍历所有redis连接实例,若存在redis实例使用该ssh隧道机器,则返回true,表示还在使用中...
|
||||||
items := poolGroup.AllPool()
|
items := poolGroup.AllPool()
|
||||||
for _, v := range items {
|
for _, v := range items {
|
||||||
if v.Stats().TotalConns == 0 {
|
rc, err := v.Get(context.Background(), pool.WithGetNoUpdateLastActive(), pool.WithGetNoNewConn())
|
||||||
continue // 连接池中没有连接,跳过
|
|
||||||
}
|
|
||||||
rc, err := v.Get(context.Background(), pool.WithNoUpdateLastActive())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue // 获取连接失败,跳过
|
continue // 获取连接失败,跳过
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
func (p *CachePool[T]) Get(ctx context.Context, opts ...GetOption) (T, error) {
|
||||||
var zero T
|
var zero T
|
||||||
|
|
||||||
options := getOptions{updateLastActive: true} // 默认更新 lastActive
|
options := defaultGetOptions // 默认更新 lastActive
|
||||||
for _, apply := range opts {
|
for _, apply := range opts {
|
||||||
apply(&options)
|
apply(&options)
|
||||||
}
|
}
|
||||||
@@ -75,6 +75,10 @@ func (p *CachePool[T]) Get(ctx context.Context, opts ...GetOption) (T, error) {
|
|||||||
}
|
}
|
||||||
p.mu.RUnlock()
|
p.mu.RUnlock()
|
||||||
|
|
||||||
|
if !options.newConn {
|
||||||
|
return zero, ErrNoAvailableConn
|
||||||
|
}
|
||||||
|
|
||||||
// 没有找到可用连接,升级为写锁进行创建
|
// 没有找到可用连接,升级为写锁进行创建
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
@@ -241,6 +245,7 @@ func (p *CachePool[T]) ping(conn T) bool {
|
|||||||
case <-done:
|
case <-done:
|
||||||
return result
|
return result
|
||||||
case <-time.After(2 * time.Second): // 设置超时
|
case <-time.After(2 * time.Second): // 设置超时
|
||||||
|
logx.Debug("ping timeout")
|
||||||
return false // 超时认为不可用
|
return false // 超时认为不可用
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func (p *ChanPool[T]) Get(ctx context.Context, opts ...GetOption) (T, error) {
|
|||||||
connChan := make(chan T, 1)
|
connChan := make(chan T, 1)
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
|
|
||||||
options := getOptions{updateLastActive: true} // 默认更新 lastActive
|
options := defaultGetOptions // 默认更新 lastActive
|
||||||
for _, apply := range opts {
|
for _, apply := range opts {
|
||||||
apply(&options)
|
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) {
|
func (p *ChanPool[T]) get(opts getOptions) (T, error) {
|
||||||
|
var zero T
|
||||||
// 检查连接池是否已关闭
|
// 检查连接池是否已关闭
|
||||||
p.mu.RLock()
|
p.mu.RLock()
|
||||||
if p.closed {
|
if p.closed {
|
||||||
p.mu.RUnlock()
|
p.mu.RUnlock()
|
||||||
var zero T
|
|
||||||
return zero, ErrPoolClosed
|
return zero, ErrPoolClosed
|
||||||
}
|
}
|
||||||
p.mu.RUnlock()
|
p.mu.RUnlock()
|
||||||
@@ -133,6 +133,9 @@ func (p *ChanPool[T]) get(opts getOptions) (T, error) {
|
|||||||
}
|
}
|
||||||
return wrapper.conn, nil
|
return wrapper.conn, nil
|
||||||
default:
|
default:
|
||||||
|
if !opts.newConn {
|
||||||
|
return zero, ErrNoAvailableConn
|
||||||
|
}
|
||||||
return p.createConn()
|
return p.createConn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrPoolClosed = errors.New("pool is closed")
|
var (
|
||||||
|
ErrPoolClosed = errors.New("pool is closed")
|
||||||
|
ErrNoAvailableConn = errors.New("no available connection")
|
||||||
|
)
|
||||||
|
|
||||||
// PoolConfig 连接池配置
|
// PoolConfig 连接池配置
|
||||||
type PoolConfig[T Conn] struct {
|
type PoolConfig[T Conn] struct {
|
||||||
@@ -71,11 +74,26 @@ type GetOption func(*getOptions)
|
|||||||
// 控制 Get 行为的选项
|
// 控制 Get 行为的选项
|
||||||
type getOptions struct {
|
type getOptions struct {
|
||||||
updateLastActive bool // 是否更新 lastActive,默认 true
|
updateLastActive bool // 是否更新 lastActive,默认 true
|
||||||
|
newConn bool // 连接不存在时是否创建新连接,默认 true
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithNoUpdateLastActive 返回一个 Option,禁用更新 lastActive
|
var (
|
||||||
func WithNoUpdateLastActive() GetOption {
|
defaultGetOptions = getOptions{
|
||||||
|
updateLastActive: true,
|
||||||
|
newConn: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithGetNoUpdateLastActive 返回一个 Option,禁用更新 lastActive
|
||||||
|
func WithGetNoUpdateLastActive() GetOption {
|
||||||
return func(o *getOptions) {
|
return func(o *getOptions) {
|
||||||
o.updateLastActive = false
|
o.updateLastActive = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithGetNoCreateConn 禁用获取时连接不存在创建连接
|
||||||
|
func WithGetNoNewConn() GetOption {
|
||||||
|
return func(o *getOptions) {
|
||||||
|
o.newConn = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ func (pg *PoolGroup[T]) asyncClose(pool Pool[T], key string) {
|
|||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
logx.Infof("pool group - pool closed successfully, key: %s", key)
|
logx.Infof("pool group - pool closed successfully, key: %s", key)
|
||||||
case <-time.After(5 * time.Second):
|
case <-time.After(10 * time.Second):
|
||||||
logx.Errorf("pool group - pool close timeout, possible deadlock detected, key: %s", key)
|
logx.Errorf("pool group - pool close timeout, key: %s", key)
|
||||||
// 打印当前 goroutine 的堆栈信息
|
// 打印当前 goroutine 的堆栈信息
|
||||||
buf := make([]byte, 1<<16)
|
buf := make([]byte, 1<<16)
|
||||||
runtime.Stack(buf, true)
|
runtime.Stack(buf, true)
|
||||||
|
|||||||
Reference in New Issue
Block a user