mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 07:50:25 +08:00
@@ -59,7 +59,6 @@ export default {
|
|||||||
docJsonError: 'Document JSON Format Error',
|
docJsonError: 'Document JSON Format Error',
|
||||||
sortParams: 'Sort',
|
sortParams: 'Sort',
|
||||||
otherParams: 'Other',
|
otherParams: 'Other',
|
||||||
previewParams: 'Preview',
|
|
||||||
closeIndexConfirm: 'This operation will close index [{name}]. Do you want to continue?',
|
closeIndexConfirm: 'This operation will close index [{name}]. Do you want to continue?',
|
||||||
openIndexConfirm: 'This operation will open index [{name}]. Do you want to continue?',
|
openIndexConfirm: 'This operation will open index [{name}]. Do you want to continue?',
|
||||||
clearCacheConfirm: 'This operation will clear index [{name}] cache. Do you want to continue?',
|
clearCacheConfirm: 'This operation will clear index [{name}] cache. Do you want to continue?',
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ export default {
|
|||||||
docJsonError: '文档JSON格式错误',
|
docJsonError: '文档JSON格式错误',
|
||||||
sortParams: '排序',
|
sortParams: '排序',
|
||||||
otherParams: '其他',
|
otherParams: '其他',
|
||||||
previewParams: '预览',
|
|
||||||
closeIndexConfirm: '将会关闭索引:[{name}]。 确认继续吗?',
|
closeIndexConfirm: '将会关闭索引:[{name}]。 确认继续吗?',
|
||||||
openIndexConfirm: '将会打开索引:[{name}]。 确认继续吗?',
|
openIndexConfirm: '将会打开索引:[{name}]。 确认继续吗?',
|
||||||
clearCacheConfirm: '将会清除索引:[{name}]缓存。 确认继续吗?',
|
clearCacheConfirm: '将会清除索引:[{name}]缓存。 确认继续吗?',
|
||||||
|
|||||||
@@ -116,7 +116,6 @@
|
|||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div>
|
<div>
|
||||||
<el-button size="small" @click="onPreviewParam" icon="view">{{ t('es.previewParams') }}</el-button>
|
|
||||||
<el-button size="small" @click="onClearParam" icon="refresh">{{ t('common.reset') }}</el-button>
|
<el-button size="small" @click="onClearParam" icon="refresh">{{ t('common.reset') }}</el-button>
|
||||||
<!-- <el-button size="small" @click="onSaveParam" type="primary" icon="check">{{ t('common.save') }}</el-button>-->
|
<!-- <el-button size="small" @click="onSaveParam" type="primary" icon="check">{{ t('common.save') }}</el-button>-->
|
||||||
|
|
||||||
@@ -472,7 +471,7 @@ const onSaveParam = () => {
|
|||||||
// 保存查询条件
|
// 保存查询条件
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPreviewParam = () => {
|
const onSearch = () => {
|
||||||
parseParams();
|
parseParams();
|
||||||
MonacoEditorBox({
|
MonacoEditorBox({
|
||||||
content: JSON.stringify(state.search, null, 2),
|
content: JSON.stringify(state.search, null, 2),
|
||||||
@@ -480,7 +479,10 @@ const onPreviewParam = () => {
|
|||||||
language: 'json',
|
language: 'json',
|
||||||
width: state.searchBoxWidth,
|
width: state.searchBoxWidth,
|
||||||
canChangeLang: false,
|
canChangeLang: false,
|
||||||
options: { wordWrap: 'on', tabSize: 2, readOnly: true }, // 自动换行
|
options: { wordWrap: 'on', tabSize: 2, readOnly: false }, // 自动换行
|
||||||
|
confirmFn: (val: string) => {
|
||||||
|
emit('search', JSON.parse(val));
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -572,11 +574,6 @@ const parseParams = () => {
|
|||||||
delete state.search['minimum_should_match'];
|
delete state.search['minimum_should_match'];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSearch = () => {
|
|
||||||
parseParams();
|
|
||||||
emit('search', state.search);
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func (app *instanceAppImpl) GetPageList(condition *entity.InstanceQuery, orderBy
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *instanceAppImpl) DoConn(ctx context.Context, instanceId uint64, fn func(*esi.EsConn) error) error {
|
func (app *instanceAppImpl) DoConn(ctx context.Context, instanceId uint64, fn func(*esi.EsConn) error) error {
|
||||||
p, err := poolGroup.GetChanPool(fmt.Sprintf("es-%d", instanceId), func() (*esi.EsConn, error) {
|
p, err := poolGroup.GetCachePool(fmt.Sprintf("es-%d", instanceId), func() (*esi.EsConn, error) {
|
||||||
return app.createConn(context.Background(), instanceId)
|
return app.createConn(context.Background(), instanceId)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package pool
|
package pool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"mayfly-go/pkg/logx"
|
"mayfly-go/pkg/logx"
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
)
|
)
|
||||||
@@ -11,12 +14,16 @@ type PoolGroup[T Conn] struct {
|
|||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
poolGroup map[string]Pool[T]
|
poolGroup map[string]Pool[T]
|
||||||
createGroup singleflight.Group
|
createGroup singleflight.Group
|
||||||
|
closingWg sync.WaitGroup
|
||||||
|
closingMu sync.Mutex
|
||||||
|
closingCh chan struct{} // 添加关闭通道
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPoolGroup[T Conn]() *PoolGroup[T] {
|
func NewPoolGroup[T Conn]() *PoolGroup[T] {
|
||||||
return &PoolGroup[T]{
|
return &PoolGroup[T]{
|
||||||
poolGroup: make(map[string]Pool[T]),
|
poolGroup: make(map[string]Pool[T]),
|
||||||
createGroup: singleflight.Group{},
|
createGroup: singleflight.Group{},
|
||||||
|
closingCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,28 +93,92 @@ func (pg *PoolGroup[T]) Get(key string) (Pool[T], bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加一个异步关闭的辅助函数
|
||||||
|
func (pg *PoolGroup[T]) asyncClose(pool Pool[T], key string) {
|
||||||
|
pg.closingMu.Lock()
|
||||||
|
pg.closingWg.Add(1)
|
||||||
|
pg.closingMu.Unlock()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
pg.closingMu.Lock()
|
||||||
|
pg.closingWg.Done()
|
||||||
|
pg.closingMu.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 设置超时检测
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
pool.Close()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 等待关闭完成或超时
|
||||||
|
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)
|
||||||
|
// 打印当前 goroutine 的堆栈信息
|
||||||
|
buf := make([]byte, 1<<16)
|
||||||
|
runtime.Stack(buf, true)
|
||||||
|
logx.Errorf("pool group - goroutine stack trace:\n%s", buf)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
func (pg *PoolGroup[T]) Close(key string) error {
|
func (pg *PoolGroup[T]) Close(key string) error {
|
||||||
pg.mu.Lock()
|
pg.mu.Lock()
|
||||||
defer pg.mu.Unlock()
|
|
||||||
|
|
||||||
if p, ok := pg.poolGroup[key]; ok {
|
if p, ok := pg.poolGroup[key]; ok {
|
||||||
logx.Infof("pool group - close pool, key: %s", key)
|
logx.Infof("pool group - closing pool, key: %s", key)
|
||||||
p.Close()
|
|
||||||
pg.createGroup.Forget(key)
|
pg.createGroup.Forget(key)
|
||||||
delete(pg.poolGroup, key)
|
delete(pg.poolGroup, key)
|
||||||
|
pg.mu.Unlock()
|
||||||
|
pg.asyncClose(p, key)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
pg.mu.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pg *PoolGroup[T]) CloseAll() {
|
func (pg *PoolGroup[T]) CloseAll() {
|
||||||
pg.mu.Lock()
|
pg.mu.Lock()
|
||||||
defer pg.mu.Unlock()
|
pools := make(map[string]Pool[T], len(pg.poolGroup))
|
||||||
|
for k, v := range pg.poolGroup {
|
||||||
for key := range pg.poolGroup {
|
pools[k] = v
|
||||||
pg.poolGroup[key].Close()
|
|
||||||
pg.createGroup.Forget(key)
|
|
||||||
}
|
}
|
||||||
pg.poolGroup = make(map[string]Pool[T])
|
pg.poolGroup = make(map[string]Pool[T])
|
||||||
|
pg.mu.Unlock()
|
||||||
|
|
||||||
|
// 异步关闭所有池
|
||||||
|
for key, pool := range pools {
|
||||||
|
pg.asyncClose(pool, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加一个用于监控连接池关闭状态的方法
|
||||||
|
func (pg *PoolGroup[T]) WaitForClose(timeout time.Duration) error {
|
||||||
|
// 创建一个新的通道用于通知等待完成
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
// 启动一个 goroutine 来等待所有关闭操作完成
|
||||||
|
go func() {
|
||||||
|
pg.closingWg.Wait()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 等待完成或超时
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return nil
|
||||||
|
case <-time.After(timeout):
|
||||||
|
// 在超时时打印当前状态
|
||||||
|
pg.mu.RLock()
|
||||||
|
remainingPools := len(pg.poolGroup)
|
||||||
|
pg.mu.RUnlock()
|
||||||
|
logx.Errorf("pool group - close timeout, remaining pools: %d", remainingPools)
|
||||||
|
return fmt.Errorf("wait for pool group close timeout after %v", timeout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pg *PoolGroup[T]) AllPool() map[string]Pool[T] {
|
func (pg *PoolGroup[T]) AllPool() map[string]Pool[T] {
|
||||||
|
|||||||
@@ -183,11 +183,11 @@ func TestCachePool_Basic(t *testing.T) {
|
|||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
conn1, _ := pool.Get(ctx)
|
conn1, _ := pool.Get(ctx)
|
||||||
|
_ = pool.Put(conn1)
|
||||||
conn2, _ := pool.Get(ctx)
|
conn2, _ := pool.Get(ctx)
|
||||||
if conn1 != conn2 {
|
if conn1 != conn2 {
|
||||||
t.Fatal("缓存池应复用同一连接")
|
t.Fatal("缓存池应复用同一连接")
|
||||||
}
|
}
|
||||||
_ = pool.Put(conn1)
|
|
||||||
_ = pool.Put(conn2)
|
_ = pool.Put(conn2)
|
||||||
pool.Close()
|
pool.Close()
|
||||||
}
|
}
|
||||||
@@ -564,6 +564,12 @@ func TestPoolGroup_ConcurrentAccess(t *testing.T) {
|
|||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
|
// 等待所有池关闭完成
|
||||||
|
err := group.WaitForClose(10 * time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("等待池关闭超时: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// 验证所有池都已关闭
|
// 验证所有池都已关闭
|
||||||
pools = group.AllPool()
|
pools = group.AllPool()
|
||||||
if len(pools) != 0 {
|
if len(pools) != 0 {
|
||||||
@@ -597,6 +603,12 @@ func TestPoolGroup_ConcurrentClose(t *testing.T) {
|
|||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
|
// 等待所有池关闭完成
|
||||||
|
err := group.WaitForClose(10 * time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("等待池关闭超时: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// 验证所有池都已关闭
|
// 验证所有池都已关闭
|
||||||
pools := group.AllPool()
|
pools := group.AllPool()
|
||||||
if len(pools) != 0 {
|
if len(pools) != 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user